RecyclerViewでドラッグしてスワイプします。 パート2:コントローラー、グリッド、およびカスタムアニメーションのドラッグアンドドロップ

RecyclerViewでドラッグしてスワイプします。パート2:コントローラー、グリッド、およびカスタムアニメーションのドラッグアンドドロップ


最初の部分では、 ItemTouchHelperItemTouchHelper.Callbackの実装を確認しました 。これは、基本的なドラッグアンドドロップおよびスワイプして 閉じる 機能RecyclerView追加します 。 この記事では、グリッド、ドラッグアンドドロップコントローラー、リストアイテムの選択、カスタムスワイプアニメーションの形式での要素の配置のサポートを追加することで、前の記事で行ったことを継続します。


要素グリッド


ドラッグアンドドロップコントローラー


ドラッグ&ドロップをサポートするリストを作成する場合、通常、アイテムをタッチでドラッグアンドドロップする機能を実装します。 これは、「編集モード」でのリストの明快さと使いやすさに貢献しており重要なガイドラインでも推奨されています。 この例にドラッグアンドドロップコントローラーを追加するのは非常に簡単です。


ドラッグアンドドロップコントローラー


まず、要素( item_main.xml )のlayout更新しlayout


 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/item" android:layout_width="match_parent" android:layout_height="?listPreferredItemHeight" android:clickable="true" android:focusable="true" android:foreground="?selectableItemBackground"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="16dp" android:textAppearance="?android:attr/textAppearanceMedium" /> <ImageView android:id="@+id/handle" android:layout_width="?listPreferredItemHeight" android:layout_height="match_parent" android:layout_gravity="center_vertical|right" android:scaleType="center" android:src="@drawable/ic_reorder_grey_500_24dp" /> </FrameLayout> 

ドラッグコントローラーに使用される画像は、 マテリアルデザインアイコンにあり、Android Studioの便利なアイコンジェネレータープラグインを使用してプロジェクトに追加できます


前の記事で簡単に説明したように、 ItemTouchHelper.startDrag(ViewHolder)を使用して、プログラムでドラッグアンドドロップを開始できます。 したがって、必要なことは、ドラッグコントローラーを追加してViewHolder更新し、 startDrag()を呼び出す単純なタッチハンドラーを設定することだけです。


チェーンに沿ってイベントを渡すためのインターフェースが必要になります。


 public interface OnStartDragListener { /** * Called when a view is requesting a start of a drag. * * @param viewHolder The holder of the view to drag. */ void onStartDrag(RecyclerView.ViewHolder viewHolder); } 

次に、 ItemViewHolderドラッグコントローラーのImageViewを定義します。


 public final ImageView handleView; public ItemViewHolder(View itemView) { super(itemView); // ... handleView = (ImageView) itemView.findViewById(R.id.handle); } 

そして、 RecyclerListAdapterを更新します。


 private final OnStartDragListener mDragStartListener; public RecyclerListAdapter(OnStartDragListener dragStartListener) { mDragStartListener = dragStartListener; // ... } @Override public void onBindViewHolder(final ItemViewHolder holder, int position) { // ... holder.handleView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { mDragStartListener.onStartDrag(holder); } return false; } }); } 

RecyclerListAdapterは次のようになります


OnStartDragListenerは、 OnStartDragListenerをフラグメントに追加するOnStartDragListenerです。


 public class RecyclerListFragment extends Fragment implements OnStartDragListener { // ... @Override public void onViewCreated(View view, Bundle icicle) { super.onViewCreated(view, icicle); RecyclerListAdapter a = new RecyclerListAdapter(this); // ... } @Override public void onStartDrag(RecyclerView.ViewHolder viewHolder) { mItemTouchHelper.startDrag(viewHolder); } } 

RecyclerListFragmentは、次のようになります 。 これで、アプリケーションを起動すると、コントローラーにタッチしてドラッグアンドドロップを開始できます。


リストアイテムのドラッグ


リストアイテムの強調表示


この例では、ドラッグされているアイテムの視覚的な表示はありません。 これは当然のことではありませんが、修正は簡単です。 ItemTouchHelperを使用すると、標準のアイテム強調表示効果を使用できます。 Lollipop以降のAndroidバージョンでは、要素とのやり取りの過程でバックライトが要素に「広がり」ます。 以前のバージョンでは、要素の色が暗くなりました。


この例を実装するにFrameLayout要素のルートFrameLayout背景( backgroundプロパティ)を追加するか、 RecyclerListAdapter.ItemViewHolderコンストラクターで設定します。 次のようになります。


要素の選択


見た目はかっこいいですが、さらに制御したい場合があります。 これを行う1つの方法は、 ViewHolder要素の状態変更ViewHolder処理できるようにすることViewHolder 。 このため、 ItemTouchHelper.Callbackはさらに2つのメソッドを提供します。



それでは、すべてをまとめましょう。


最初に、 ViewHoldersが実装するインターフェイスを作成します。


 /** * Notifies a View Holder of relevant callbacks from * {@link ItemTouchHelper.Callback}. */ public interface ItemTouchHelperViewHolder { /** * Called when the {@link ItemTouchHelper} first registers an * item as being moved or swiped. * Implementations should update the item view to indicate * it's active state. */ void onItemSelected(); /** * Called when the {@link ItemTouchHelper} has completed the * move or swipe, and the active item state should be cleared. */ void onItemClear(); } 

次に、 SimpleItemTouchHelperCallback 、適切なメソッドを実装します。


 @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { // We only want the active item if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { if (viewHolder instanceof ItemTouchHelperViewHolder) { ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; itemViewHolder.onItemSelected(); } } super.onSelectedChanged(viewHolder, actionState); } @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); if (viewHolder instanceof ItemTouchHelperViewHolder) { ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder; itemViewHolder.onItemClear(); } } 

今残っているのは、 RecyclerListAdapter.ItemViewHolder ItemTouchHelperViewHolder RecyclerListAdapter.ItemViewHolder実装RecyclerListAdapter.ItemViewHolderことItemTouchHelperViewHolderです:


 public class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder { // ... @Override public void onItemSelected() { itemView.setBackgroundColor(Color.LTGRAY); } @Override public void onItemClear() { itemView.setBackgroundColor(0); } } 

この例では、要素がアクティブなときに灰色の背景を追加してから削除します。 ItemTouchHelperとアダプターが密接に接続されている場合、この設定を簡単に破棄し、 ItemTouchHelper.Callback viewコンポーネントの状態を直接切り替えることができます。


ネット


GridLayoutManagerを使用しようとすると、正しく動作しないことがわかります。 理由と解決策は簡単です。アイテムの左右へのドラッグをサポートすることをItemTouchHelperに伝える必要があります。 SimpleItemTouchHelperCallback前半で、既に指定しました:


 @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } 

グリッドをサポートするために必要な唯一の変更は、適切なフラグを追加することです。


 int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; 

ただし、 スワイプしswipeFlags 、グリッド要素の自然な動作でないため、 swipeFlagsほとんどswipeFlagsます。


 @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); } 

動作するGridLayoutManager例を確認するには、 RecyclerGridFragmentを参照してください。 起動時の外観は次のとおりです。


グリッド要素


カスタムスワイプアニメーション


ItemTouchHelper.Callbackは、ドラッグアンドドロップ中にアニメーションを完全に制御するための非常に便利な方法を提供します。 ItemTouchHelperRecyclerView.ItemDecorationであるため、同様の方法でviewコンポーネントをレンダリングするプロセスに介入できます。 次のパートでは、この質問をさらに詳しく調べますが、ここでは、デフォルトのスワイプアニメーションをオーバーライドして線形消失を示す簡単な例を見てみましょう。


 @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { float width = (float) viewHolder.itemView.getWidth(); float alpha = 1.0f - Math.abs(dX) / width; viewHolder.itemView.setAlpha(alpha); viewHolder.itemView.setTranslationX(dX); } else { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } } 

dXおよびdYは、選択したviewコンポーネントに対する現在のシフトです。ここで、



デフォルトのアニメーションをトリガーするには、処理していないactionStateに対してsuperを呼び出すことが重要です。


次のパートでは、ドラッグアンドドロップ時に要素の描画を制御する例を検討します。


おわりに


実際、ItemTouchHelperのセットアップはとても楽しいです。 この記事の量を増やしないために、私はそれをいくつかに分けました。


ソースコード


Android-ItemTouchHelper-Demo GitHubリポジトリでこの記事シリーズの完全なコードを参照してください。 この記事では、 ef8f149からd164fbaへのコミットについて説明します


←RecyclerViewでドラッグしてスワイプします。 パート1:ItemTouchHelper



Source: https://habr.com/ru/post/J428419/


All Articles