11

Ho un problema con ItemTouchHelper di RecyclerView.android - come catturare l'azione Drop di ItemTouchHelper che viene utilizzato con RecyclerView

Sto facendo un gioco. Il tabellone di gioco è in realtà un RecyclerView. RecyclerView ha GridLayoutManager con un certo numero di span. Voglio implementare trascinare & eliminare elementi di recyclerview. Qualsiasi oggetto può trascinare su tutte le direzioni (su, giù, sinistra, destra).

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); 
} 

è così, perché la funzione di onMoved ItemTouchHelper funziona quando ancora si trascina punto all'ordine del RecyclerView? Come posso raggiungere questo obiettivo ?

risposta

35

Su di una volta di "drag & goccia ", onMove() verrà chiamato più volte, ma clearView() sarà cal guidato una volta. Quindi puoi usare questo per indicare che il trascinamento era finito (la caduta era avvenuta). E utilizzare due variabili dragFrom e dragTo per tracciare la posizione effettiva in un "trascinamento & rilascio".

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) era come di seguito:

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

+0

stavo cercando questo: =) – Beyaz

+0

funziona come previsto – andre719mv

+0

ho cercato di capire come sapere il calo è stato completato. La tua spiegazione di clearView() è perfetta. Grazie per aver mostrato anche l'implementazione. – seekingStillness

2

Il onSelectedChanged(RecyclerView.ViewHolder, int) callback fornisce informazioni sulla actionState corrente:
- ACTION_STATE_IDLE:
- ACTION_STATE_DRAG
- ACTION_STATE_SWIPE

In questo modo è possibile monitorare se l'ordine è stato modificato e quando lo stato diventa ACTION_STATE_IDLE, è possibile eseguire ciò che è necessario fare!

Esempio:

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

Questa è stata anche la mia risposta intuitiva, ma a quanto pare non funziona come previsto ... –

+0

Ha funzionato per me. Cosa non funziona per te? –

+0

Ho usato con successo un metodo come questo, rintracciando lo stato precedente ogni volta che veniva chiamato 'onSelectedChanged' - se USATO fosse' ACTION_STATE_DRAG' e ora 'ACTION_STATE_IDLE' quindi' doSomething() ' – andygeers

Problemi correlati