RecyclerView使用ItemTouchHelper实现拖拽排序
一、目标
拖拽完成文件夹收藏排序。
通过拖拽右侧拖拽按钮,实现文件夹收藏排序。
二、体验地址
神马笔记最新版本:【神马笔记 版本1.3.0.apk】
三、功能设计
收藏文件夹时,总是添加到第一个位置,显示在列表最上方。
当收藏的文件夹数量增加时,需要对收藏进行排序,方便查找。
常见的几种排序方式:
- 手动排序
- 名称
- ……
这里,我们使用手动排序方式。
四、准备工作
1. ItemTouchHelper
ItemTouchHelper有2个功能:
- 拖拽——调整列表项顺序
- 侧向滑动——删除列表项
public ItemTouchHelper(Callback callback);
public void attachToRecyclerView(@Nullable RecyclerView recyclerView);
public void startDrag(ViewHolder viewHolder);
public void startSwipe(ViewHolder viewHolder);
ItemTouchHelper
提供给外部调用的接口主要有以上4个。
- 创建ItemTouchHelper对象
- 附加到
RecyclerView
上 - 开始拖拽
- 开始侧向滑动
ItemTouchHelper
的行为由Callback
对象来决定,使用ItemTouchHelper
的关键在于实现Callback
接口。
2. ItemTouchHelper.Callback
将Callback
的需要实现的接口,分为4个类别。
- 必须实现的抽象方法
// 必须通过makeMovementFlags返回值,上、下、左、右四个方向
// SimpleCallback提供了该方法的一个实现版本
public abstract int getMovementFlags(RecyclerView recyclerView,
ViewHolder viewHolder);
// 发生拖拽事件
public abstract boolean onMove(RecyclerView recyclerView,
ViewHolder viewHolder, ViewHolder target);
// 发生侧滑事件
public abstract void onSwiped(ViewHolder viewHolder, int direction);
- 拖拽行为接口
// 是否支持长按触发拖拽
public boolean isLongPressDragEnabled() {
return true;
}
// 是否可以放置到target位置
public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
ViewHolder target) {
return true;
}
// 触发移动的阈值
public float getMoveThreshold(ViewHolder viewHolder) {
return .5f;
}
- 侧滑行为接口
// Item是否支持侧向滑动
public boolean isItemViewSwipeEnabled() {
return true;
}
// 侧滑事件的滑动距离触发值
public float getSwipeThreshold(ViewHolder viewHolder) {
return .5f;
}
// 侧滑事件的速度触发值
public float getSwipeEscapeVelocity(float defaultValue) {
return defaultValue;
}
// ???
public float getSwipeVelocityThreshold(float defaultValue) {
return defaultValue;
}
- UI相关接口(包括拖拽及侧滑)
// 选中目标Item时
public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
if (viewHolder != null) {
sUICallback.onSelected(viewHolder.itemView);
}
}
// 动作完成时
public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
sUICallback.clearView(viewHolder.itemView);
}
// ItemDecoration#onDraw
public void onChildDraw(Canvas c, RecyclerView recyclerView,
ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
sUICallback.onDraw(c, recyclerView, viewHolder.itemView, dX, dY, actionState,
isCurrentlyActive);
}
// ItemDecoration#onDrawOver
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
ViewHolder viewHolder,
float dX, float dY,
int actionState, boolean isCurrentlyActive) {
sUICallback.onDrawOver(c, recyclerView, viewHolder.itemView