11

で使用されてItemTouchHelperのドロップアクションをキャッチする方法について説明します。アンドロイド - 私は<strong>ItemTouchHelper</strong><strong>のRecyclerView</strong>に問題があるRecyclerView

私はゲームを作っています。ゲームボードは実際にはRecyclerViewです。 RecyclerViewには、ある程度のスパン数を持つGridLayoutManagerがあります。私はを実装したい&ドロップ recyclerviewの項目をドラッグします。どの項目もすべての方向(上、下、左、右)にドラッグできます。

private void initializeLayout() { 
    recyclerView.setHasFixedSize(true); 
    recyclerView.setLayoutFrozen(true); 
    recyclerView.setNestedScrollingEnabled(false); 

    // set layout manager 
    GridLayoutManager layoutManager = new GridLayoutManager(getContext(), BOARD_SIZE, 
     LinearLayoutManager.VERTICAL, true); 
    recyclerView.setLayoutManager(layoutManager); 

    // Extend the Callback class 
    ItemTouchHelper.Callback itemTouchCallback = new ItemTouchHelper.Callback() { 

    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 
     Log.w(TAG, "onMove"); 
     return false; 
    } 

    @Override 
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 
     // Application does not include swipe feature. 
    } 

    @Override 
    public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, 
         int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) { 
     Log.d(TAG, "onMoved"); 
     // this is calling every time, but I need only when user dropped item, not after every onMove function. 
    } 

    @Override 
    public boolean isItemViewSwipeEnabled() { 
     return false; 
    } 

    @Override 
    public boolean isLongPressDragEnabled() { 
     return true; 
    } 

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

    ItemTouchHelper touchHelper = new ItemTouchHelper(itemTouchCallback); 
    touchHelper.attachToRecyclerView(recyclerView); 
} 

私はまだRecyclerView上のアイテムをドラッグするときSO、なぜItemTouchHelperのonMoved機能が動作しますか?どうすればこれを達成できますか?

答えて

35

をやってこの男のように

Collections.swap(youCoolList, fromPosition, toPosition); notifyItemMoved(fromPosition, toPosition);

を"の場合、onMove()は複数回呼び出されますが、clearView()はcal一度リードした。だからあなたはドラッグが終了した(ドロップが起こった)ことを示すためにこれを使うことができます。 そして、2つの変数dragFromとdragToを使用して、完成した "drag &ドロップ"の実際の位置をトレースします。

private ItemTouchHelper.Callback dragCallback = new ItemTouchHelper.Callback() { 

    int dragFrom = -1; 
    int dragTo = -1; 

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

    @Override 
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 

     int fromPosition = viewHolder.getAdapterPosition(); 
     int toPosition = target.getAdapterPosition(); 


     if(dragFrom == -1) { 
      dragFrom = fromPosition; 
     } 
     dragTo = toPosition; 

     adapter.onItemMove(fromPosition, toPosition); 

     return true; 
    } 

    private void reallyMoved(int from, int to) { 
     // I guessed this was what you want... 
    } 

    @Override 
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 

    } 

    @Override 
    public boolean isLongPressDragEnabled() { 
     return true; 
    } 

    @Override 
    public boolean isItemViewSwipeEnabled() { 
     return false; 
    } 

    @Override 
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 
     super.clearView(recyclerView, viewHolder); 

     if(dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) { 
      reallyMoved(dragFrom, dragTo); 
     } 

     dragFrom = dragTo = -1; 
    } 

}; 

adapter.onItemMove(FromPositionは、toPosition)は以下のようであった:

list.add(toPosition, list.remove(fromPosition)); notifyItemMoved(fromPosition, toPosition);

+0

私はこれを見ていた:=を)期待通り – Beyaz

+0

作品 – andre719mv

+0

私は、ドロップが完了している知っている方法を把握しようとしてきました。 clearView()のあなたの説明は完璧です。実装の表示にも感謝します。 – seekingStillness

2

onSelectedChanged(RecyclerView.ViewHolder, int)コールバックは、現在actionStateについての情報を提供し:
- ACTION_STATE_IDLE
- ACTION_STATE_DRAG
- ACTION_STATE_SWIPE

注文が変更されたかどうかを追跡でき、状態がACTION_STATE_IDLEに変更されたときには、必要な作業を行うことができます。

例:

private final class MyCallback extends ItemTouchHelper.Callback { 
    private boolean mOrderChanged; 

    @Override 
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 
     // Check if positions of viewHolders correspond to underlying model, and if not, flip the items in the model and set the mOrderChanged flag 
     mOrderChanged = true; 
    } 

    @Override 
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { 
    super.onSelectedChanged(viewHolder, actionState); 

    if (actionState == ItemTouchHelper.ACTION_STATE_IDLE && mOrderChanged) { 
     doSomething(); 
     mOrderChanged = false; 
    } 
} 
+0

これも私の直感的な答えでしたが、明らかに期待どおりに動作しません... –

+0

それは私のために働いた。何があなたのために働いていないのですか? –

+0

'onSelectedChanged'が呼び出されるたびに以前の状態を追跡することでこのようなメソッドを使いました。これはUSEDが' ACTION_STATE_DRAG'で、現在は 'ACTION_STATE_IDLE'で' doSomething() ' – andygeers

関連する問題