recycleritemtouchhelper - swipe menu recyclerview android
Android: cómo capturar la acción Drop de ItemTouchHelper que se usa con RecyclerView (4)
Debe realizar la escucha OnMove en su adaptador:
Collections.swap(youCoolList, fromPosition, toPosition); notifyItemMoved(fromPosition, toPosition);
como este hombre haciendo https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf#.blviq6jxp
ejemplo de cuadrícula especial https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.xb74uu7ke
Tengo un problema con ItemTouchHelper de RecyclerView .
Estoy haciendo un juego. El tablero de juego es en realidad un RecyclerView. RecyclerView tiene GridLayoutManager con algunos recuentos de intervalo. Quiero implementar los elementos de arrastrar y soltar recyclerview. Cualquier elemento puede arrastrar sobre todas las direcciones (arriba, abajo, izquierda, derecha).
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);
}
Entonces, ¿por qué la función onMoved de ItemTouchHelper funciona cuando sigo arrastrando un elemento en RecyclerView? Cómo puedo conseguir esto ?
Hice algunas pruebas y onSelectedChanged(RecyclerView.ViewHolder?, Int)
pareció más confiable para detectar el final del gesto (soltar). Se llama al método siempre que se arrastra un elemento y se pasa el estado de acción de ACTION_STATE_DRAG
. Cuando finaliza el arrastre, se llama con el estado de acción de ACTION_STATE_IDLE
.
Vea mi solución a continuación. La devolución de llamada onItemDrag(Int, Int)
se utiliza para reordenar los elementos en un adaptador a medida que se arrastra el elemento. Por otro lado, la devolución de llamada onItemDragged(Int, Int)
está destinada a actualizar las posiciones en una base de datos al final del gesto.
class ItemGestureHelper(private val listener: OnItemGestureListener) : ItemTouchHelper.Callback() {
interface OnItemGestureListener {
fun onItemDrag(fromPosition: Int, toPosition: Int): Boolean
fun onItemDragged(fromPosition: Int, toPosition: Int)
fun onItemSwiped(position: Int)
}
private var dragFromPosition = -1
private var dragToPosition = -1
// Other methods omitted...
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
// Item is being dragged, keep the current target position
dragToPosition = target.adapterPosition
return listener.onItemDrag(viewHolder.adapterPosition, target.adapterPosition)
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
listener.onItemSwiped(viewHolder.adapterPosition)
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
when (actionState) {
ItemTouchHelper.ACTION_STATE_DRAG -> {
viewHolder?.also { dragFromPosition = it.adapterPosition }
}
ItemTouchHelper.ACTION_STATE_IDLE -> {
if (dragFromPosition != -1 && dragToPosition != -1 && dragFromPosition != dragToPosition) {
// Item successfully dragged
listener.onItemDragged(dragFromPosition, dragToPosition)
// Reset drag positions
dragFromPosition = -1
dragToPosition = -1
}
}
}
}
}
La devolución de llamada onSelectedChanged(RecyclerView.ViewHolder, int)
proporciona información sobre el estado de acción actual:
- ACTION_STATE_IDLE
:
- ACTION_STATE_DRAG
- ACTION_STATE_SWIPE
Por lo tanto, puede hacer un seguimiento de si el orden cambió y, cuando el estado cambie a ACTION_STATE_IDLE
, ¡puede hacer lo que necesita hacer!
Ejemplo:
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;
}
}
Mientras arrastra y suelta un elemento, se puede llamar a onMove () más de una vez, pero se debe llamar a clearView () una vez. Por lo tanto, puede usar esto para indicar que el arrastre había terminado (se realizó la caída). Y use dos variables, dragFrom y dragTo para rastrear la posición real en un completo "arrastrar y soltar".
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) fue como a continuación:
list.add(toPosition, list.remove(fromPosition)); notifyItemMoved(fromPosition, toPosition);