RecyclerView 滑动删除与拖动的实现
前言
记得很久以前做APP应用的时候,项目组老大说网易的栏目管理那块,可拖动排序蛮好看的,我们的应用也要那么做,后来我就在网上百度一番,找到用GridView的实现,最近游览网页,在网上看见有用RecyclerView实现的,自己也按照文章上的写了,看了一下,觉得写的蛮好的,不过有些地方的注释写的不全,所以我也写了一篇记录下来,参考文地址在这里,感谢这位作者,使我又学会了很多。
实现原理
主要是借助 ItemTouchHelper.Callback 类来实现,我们要关注的方法为
* getMovementFlags( )
* onMove()
* onSwiped()
* onSelectedChanged()
* clearView()
* isLongPressDragEnabled()
只需要重写这些方法,就能得到我们想要的结果。
拖动实现
首先自定义一个MyCallback类继承 ItemTouchHelper.Callback ,定义两个int变量dragFlags 与 swipeFlags 并实现下方法。
getMovementFlags()
这个方法主要是为了获取我们当前的事件是拖动还是滑动
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;
}
return makeMovementFlags(dragFlags, swipeFlags);
首先在这里为我们的标志符赋值为0,然后通过 ItemTouchHelper 来为标识符赋值。
onMove()
在该方法的注释中有这一段说明
viewHolder The ViewHolder which is being dragged by the user.
target The ViewHolder over which the currently active item is being dragged.
这两个都是onMove提供的参数,从注释中可以看出viewHolder是起始位置,而target是目标位置,那么我们就好办了
int fromPosition = viewHolder.getAdapterPosition();
int toPosition = target.getAdapterPosition();
//这里的toPosition和fromPosition结合可以设置那一项不能改变
if (toPosition >= 2 && fromPosition != 0 && fromPosition !=1){
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;
这里我设置了前两项不可交换位置,往往我们都会有这样的需求。通过Collections 来交换数据,最后通过ecyclerView.getAdapter().notifyItemMoved 来刷新页面。
与RecyclerView绑定
通过ItemTouchHelper的attachToRecyclerView方法与RecyclerView绑定在一起
ItemTouchHelper helper = new ItemTouchHelper(new MyItemTouchHelperCallback());
helper.attachToRecyclerView(mRecyclerView);
其中的MyItemTouchHelperCallback就是我们的自定义继承了 ItemTouchHelper.Callback 类的实现。这样并没有长按出现的效果,用户体验不好,可在下面的方法中实现。
onSelectedChanged
我们可以在这个方法中自定义用户长按后出现的效果,我这里就只设置了放大。
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setScaleX(1.05f);
viewHolder.itemView.setScaleY(1.05f);
}
如果只设置了方法,而不设置缩小。那么肯定是不行的,我们在下面的方法中去还原View。
clearView
当事件结束后,我们可以在这里做一些处理,比如上面的还原View。
viewHolder.itemView.setScaleX(1.0f);
viewHolder.itemView.setScaleY(1.0f);
到这里我们的拖动就结束了,下面我们再来实现滑动删除。
滑动删除
滑动删除和拖动也是一样的实现思路,也是通过getMovementFlags获取事件,我们在前面的代码中添加如下代码
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
这样就可以了,如果你只想GridLayoutManager或LinearLayoutManager有滑动删除,那么可以把代码添加到上面的if判断里面去。
onSwiped
删除的实现,这是一个抽象方法,我们必须实现的。
int position = viewHolder.getAdapterPosition();
mRecyclerView.getAdapter().notifyItemRemoved(position);
mListData.remove(position);
这个方法比较简单,就是删除数据,更新页面。
如果你不想你的某一些项不可以滑动删除,那么就可以在前面的getMovementFlags去做判断,只要不为swipeFlags赋值就可以了。
isLongPressDragEnabled
该方法默认所有的项都可以拖动,在这里直接返回false,然后在为
RecyclerView添加的事件监听中为长按事件添加如下代码就可以了
helper.startDrag(vh);
这样该Item项就可以拖动了,其中的helper为上面的ItemTouchHelper,vh就不用解释了吧。
如果对于RecyclerView的Item点击事件还不了解的可以阅读RecyclerView item点击你真的会么
总结
RecyclerView是如此的强大,对于滑动与拖动,只需要弄明白上面的6个方法的调用顺序,各个方法的任务。其中最重要的就是 getMovementFlags 了,如果这里弄错了,那么后面的都没用。