RecyclerView的拖动和滑动 第一部分 :基本的ItemTouchHelper示例

安卓中,有许多关于如何使用RecyclerView实现“drag & drop”与swipe-to-dismiss”的教程,库和例子。即使现在已经有了新的,更优的实现方式,大多数仍然是使用老旧的View.OnDragListener以及Roman Nurik在SwipeToDismiss中所使用的方法。很少有人使用新的api,反而要么经常依赖于GestureDetectors和onInterceptTouchEvent,要么实现方式很复杂。实际上,在RecyclerView上添加拖动特性有一个非常简单的方法。这个方法只需要一个类,并且它也是Android 兼容包的一部分,它就是:

ItemTouchHelper

ItemTouchHelper是一个强大的工具,它处理好了关于在RecyclerView上添加拖动排序与滑动删除的所有事情。它是RecyclerView.ItemDecoration的子类,也就是说它可以轻易的添加到几乎所有的LayoutManager和Adapter中。它还可以和现有的item动画一起工作,提供受类型限制的拖放动画等等,

这篇文章中,我会演示一个ItemTouchHelper的简单实现,然后在这个系列文章的后面部分,我们将拓展范围,探索一些新的特性。

跳过本文

只对完整源码感兴趣?直接跳到github: Android-ItemTouchHelper-Demo第一次提交的代码和本文的内容相对应。 在这里下载demo apk 。

设置

第一件事是RecyclerView的基本设置,修改build.gradle,添加RecyclerView的依赖。

1
compile  'com.android.support:recyclerview-v7:22.2.0'

ItemTouchHelper可以与几乎任意的RecyclerView.Adapter 和 LayoutManager使用,但是本文建立了几个基本的文件,可以在Gist上找到:


https://gist.github.com/iPaulPro/2216ea5e14818056cfcc


使用 ItemTouchHelper 和 ItemTouchHelper.Callback

要使用ItemTouchHelper,你需要创建一个ItemTouchHelper.Callback。这个接口可以让你监听“move”与 “swipe”事件。这里还是控制view被选中的状态以及重写默认动画的地方。如果你只是想要一个基本的实现,有一个帮助类可以使用:SimpleCallback,但是为了了解其工作机制,我们还是自己实现。

启用基本的拖动排序与滑动删除需要重写的主要回调方法是:

1
2
3
getMovementFlags(RecyclerView, ViewHolder)
onMove(RecyclerView, ViewHolder, ViewHolder)
onSwiped(ViewHolder, int)

我也需要两个帮助方法:

1
2
isLongPressDragEnabled()
isItemViewSwipeEnabled()

我们将一一解答上面的方法。

1
2
3
4
5
6
7
@Override
public int getMovementFlags(RecyclerView recyclerView, 
         RecyclerView.ViewHolder viewHolder) {
     int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
     int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
     return  makeMovementFlags(dragFlags, swipeFlags);
}

ItemTouchHelper可以让你轻易得到一个事件的方向。你需要重写getMovementFlags()方法来指定可以支持的拖放和滑动的方向。使用helperItemTouchHelper.makeMovementFlags(int, int)来构造返回的flag。这里我们启用了上下左右两种方向。注:上下为拖动(drag),左右为滑动(swipe)。

1
2
3
4
@Override
public boolean isLongPressDragEnabled() {
     return  true ;
}

ItemTouchHelper可以用于没有滑动的拖动操作(或者反过来),你必须指明你到底要支持哪一种。要支持长按RecyclerView item进入拖动操作,你必须在isLongPressDragEnabled()方法中返回true。或者,也可以调用ItemTouchHelper.startDrag(RecyclerView.ViewHolder) 方法来开始一个拖动。这会在后面讲到。

1
2
3
4
@Override
public boolean isItemViewSwipeEnabled() {
     return  true ;
}

而要在view任意位置触摸事件发生时启用滑动操作,则直接在sItemViewSwipeEnabled()中返回true就可以了。或者,你也主动调用ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) 来开始滑动操作。

接下来的两个是onMove()和onSwiped(),用于通知底层数据的更新。首先我们创建一个可以将这些回调方法传递出去的接口。

1
2
3
4
5
6
public interface ItemTouchHelperAdapter {
 
     void onItemMove(int fromPosition, int toPosition);
 
     void onItemDismiss(int position);
}


ItemTouchHelperAdapter.java Gist


以本例来说,最简单的方法就是在我们的RecyclerListAdapter 中实现这个listener。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RecyclerListAdapter extends 
         RecyclerView.Adapter<ItemViewHolder> 
         implements ItemTouchHelperAdapter { // ... code from gist
@Override
public void onItemDismiss(int position) {
     mItems.remove(position);
     notifyItemRemoved(position);
}
 
@Override
public void onItemMove(int from, int to) {
     Collections.swap(mItems, from, to);
     notifyItemMoved(from, to);
}

notifyItemRemoved()和 notifyItemMoved()的调用非常重要,有了它们Adapter才能知道发生了改变。同时还需要注意的是每当一个view切换到了一个新的索引时,我们都需要改变item的位置,而不是在拖动事件结束的时候。

现在我们回来创建我们的SimpleItemTouchHelperCallback,我们仍然需要重写onMove() 和 onSwiped()。

首先我们添加一个构造函数以及一个引用adapter的成员变量:

1
2
3
4
5
6
private final ItemTouchHelperAdapter mAdapter;
 
public SimpleItemTouchHelperCallback(
         ItemTouchHelperAdapter adapter) {
     mAdapter = adapter;
}

然后重写剩下的事件同时通知adapter:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public boolean onMove(RecyclerView recyclerView, 
         RecyclerView.ViewHolder viewHolder, 
         RecyclerView.ViewHolder target) {
     mAdapter.onItemMove(viewHolder.getAdapterPosition(), 
             target.getAdapterPosition());
     return  true ;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, 
         int direction) {
     mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}

这样Callback类大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
  
     private final ItemTouchHelperAdapter mAdapter;
  
     public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
         mAdapter = adapter;
     }
     
     @Override
     public boolean isLongPressDragEnabled() {
         return  true ;
     }
  
     @Override
     public boolean isItemViewSwipeEnabled() {
         return  true ;
     }
  
     @Override
     public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
         int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
         int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
         return  makeMovementFlags(dragFlags, swipeFlags);
     }
  
     @Override
     public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, 
             ViewHolder target) {
         mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
         return  true ;
     }
  
     @Override
     public void onSwiped(ViewHolder viewHolder, int direction) {
         mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
     }
  
}

Callback准备好了之后,我们就可以创建我们的ItemTouchHelper并调用attachToRecyclerView(RecyclerView) 了(参见MainFragment.java):

1
2
3
4
ItemTouchHelper.Callback callback = 
     new  SimpleItemTouchHelperCallback(adapter);
ItemTouchHelper touchHelper =  new  ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(recyclerView);

运行之后,你可以看到如下的效果:

总结

这是一个ItemTouchHelper的简单实现。但是已经阐明了在RecyclerView上实现拖动排序与滑动删除时根本不需要第三方库的。在下一部分中,我们将对被拖动或者滑动的item做更多外观上的控制。


源代码

我在github上创建了一个覆盖这个系列文章的项目:Android-ItemTouchHelper-Demo第一次提交的代码和这部分相对应的,也有点第二部分的内容。

Android应用源码45套安卓源码合集: android中文离线发音引擎FOCTTS使用源码.rar Android应用源码(精)LBS签到应用源码.rar Android应用源码(精)xUtils2.2.5.rar Android应用源码(精)仿博客园客户端源码.rar Android应用源码(精)手机控制电脑鼠标.rar Android应用源码(精)记事本小程序,加注释,适合阅读.rar Android应用源码Android平台下通过HTTP协议实现断点续传下载.rar Android应用源码Hibernate4Android.rar Android应用源码http、udp、tcp网络交互组件.rar Android应用源码ListView实现的目录树结构.rar Android应用源码SdCard读写文件实例.rar Android应用源码SlidingMenu使用例子.rar Android应用源码串口通信(JNI)例子.rar Android应用源码任务提醒源码.rar Android应用源码仿360手机助手首页浮动菜单.rar Android应用源码仿Iphone抖动效果Shake Icon.rar Android应用源码仿QQ分组列表修改版.rar Android应用源码使用listView实现的树状结构.rar Android应用源码俄罗斯方块注释超详细版.rar Android应用源码利用poi将内容填到word模板.rar Android应用源码动态列表布局.rar Android应用源码单Java文件实现的计算器.rar Android应用源码基于百度云推送的聊天工具源码.rar Android应用源码安卓多边形布局例子.rar Android应用源码安卓拍照上传实现代码附带php端.rar Android应用源码实现动态交叉布局.rar Android应用源码小说翻页效果源码.rar Android应用源码广告轮播效果源码.rar Android应用源码强大的统计图表库.rar Android应用源码微享,微信分享实例.rar Android应用源码有米广告SDK例子.rar Android应用源码模仿zaker风景页面滑动效果修改版.rar Android应用源码水波纹动画效果.rar Android应用源码泡泡效果bubble.rar Android应用源码猜猜红桃A.rar Android应用源码百度统计例子.rar Android应用源码简单的Android图片轮播.rar Android应用源码简单的仿微信实现了表情效果.rar Android应用源码结合数据库进行摇一摇的实例.rar Android应用源码花姑娘之部分UI源码.rar Android应用源码获取手机信息.rar Android应用源码讯飞语音测试源码.rar Android应用源码飞碟说欢迎界面.rar
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值