前言
前些时候提到了下RecyclerView
的点击事件的处理,今天再来说说RecyclerView
的拖动、滑动删除。看完了以后你会发现RecyclerView
是多么的犀利。比ListView
简单的多了。
原理
主要是使用ItemTouchHelper.Callback
类,在其中我们要用到的方法主要有
- getMovementFlags()
- onMove()
- onSwiped()
- isLongPressDragEnabled()
- onSelectedChanged()
- clearView()
借助该ItemTouchHelper.Callback
与其中的方法就能很好的处理实现拖动、删除。
下面详细介绍这些方法的用处与功能实现。
拖动
getMovementFlags
既然要使用ItemTouchHelper.Callback
中的方法,所以我们首先自定义自己的类来继承它,重写其中的相关方法。首先是getMovementFlags()
方法,该方法主要作用是定义移动标识,所以针对拖动效果,我们可以首先定义拖动标识,通过ItemTouchHelper
提供的参数来定义:
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
dragFlags = 0;
swipeFlags = 0;
if (recyclerView.getLayoutManager() instanceof GridLayoutManager
|| recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN
| ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
} else {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
//if (viewHolder.getAdapterPosition() != 0)
// swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
}
return makeMovementFlags(dragFlags, swipeFlags);
}
这里可以根据你的RecyclerView
的LayoutManager
情况来定义拖动方向。LinearLayoutManager
可以定义上下拖动dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
至于注释代码swipeFlags
这里先不要管,这是下面的删除标识。最后再调用makeMovementFlags
返回。
onMove
在定义完MovementFlags
以后,在我们拖动的时候回调用onMove
方法,所以我们可以重写该方法,进行对数据的改变操作。
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
if (toPosition != 0) {
if (fromPosition < toPosition)
//向下拖动
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(mListData, i, i + 1);
}
else {
//向上拖动
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(mListData, i, i - 1);
}
}
recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
}
return true;
}
通过提供的参数获取fromPosition
初始位置toPosition
目标位置,根据情况做相应的数据改变,最后调用recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
来更新adapter
状态。
绑定
最后用下面代码来绑定目标RecyclerView
对象。
final ItemTouchHelper helper = new ItemTouchHelper(new MyCallBack());
helper.attachToRecyclerView(recyclerView);
(new MyCallBack()
就是前面我自定义的类。这样基本的拖动就实现了。但是你会发现就这样的话你在拖动的时候回没有背景效果的所以我们再来进行优化一下
onSelectedChanged
通过重写该方法我们可以定义自己的拖动背景
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setPressed(true);
}
super.onSelectedChanged(viewHolder, actionState);
}
当然前提是你的RecyclerView
的Item
已经添加了android:background="@drawable/item_bg
属性。例如item_bg
:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@android:color/darker_gray"/>
</shape>
</item>
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
</shape>
</item>
</selector>
clearView
最后再重写clearViwe()
拖动完成之后会调用,用来清除背景状态。
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setPressed(false);
}
这样基本上就完成了日常我们所要的拖动效果。至于对个别的Item
屏蔽拖动效果可以重写isLongPressDragEnabled()
方法
isLongPressDragEnabled
该方法默认返回true
就是不屏蔽拖动效果,所有的Item
都能被拖动。如果要实现屏蔽的话,这里我们只要返回false
就可以了。
@Override
public boolean isLongPressDragEnabled() {
return false;
}
再在我们前面文章中定义的Item
点击事件的处理中的onItemLongPressClick()
方法中调用helper.startDrag(vh)
方法实现要拖动的Item
,通过传入要拖动的ViewHolder
来标识。
@Override
public void onItemLongPressClick(RecyclerView.ViewHolder vh) {
if (vh.getAdapterPosition() != 0) {
helper.startDrag(vh);
}
}
这里我固定了第一个位置是不能被拖动的。
如果对于RecyclerView的Item点击事件还不了解的可以阅读我前面的文章RecyclerView item点击你真的会么
滑动删除
到这里相信滑动删除应该有点眉目了吧。对,就是前面getMovementFlags()
方法中所定义的swipeFlags
标识,ItemTouchHelper
为我们提供了左右删除标识ItemTouchHelper.START
与ItemTouchHelper.END
,这样我们就可以先打开前面注释的代码。
onSwiped
最后可以在onSwiped()
中对数据进行删除操作
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int positon = viewHolder.getAdapterPosition();
recyclerView.getAdapter().notifyItemRemoved(positon);
mListData.remove(positon);
}
这样基本的滑动删除就可以实现了。至于对个别的Item
屏蔽删除效果可以重写isItemViewSwipeEnabled()
方法
isItemViewSwipeEnabled
该方法与前面的拖动的屏蔽isItemViewSwipeEnabled()
方法使用方式是一样的,它也是默认返回true
,不对Item
进行屏蔽滑动删除。如果要屏蔽的话也是重写方法再返回false
,最后在通过对应的startSwipe(ViewHolder)
方法实现滑动删除,具体的实现可以参考前面的屏蔽拖动。
总结
这里主要是要弄明白上面所提到的6个方法的作用与调用时机。主要就是getMovementFlags()
方法,定义好拖动与滑动标识。拖动时会回调onMove()
方法,滑动删除时要处理数据的删除,所以会回调onSwiped()
方法,至于其它的状态效果方法可以视需求来灵活变化。
Demo地址:https://github.com/idisfkj/Re...
欢迎访问个人blog:https://idisfkj.github.io/arc...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。