RecyclerView 拖拽与滑动操作
RecyclerView 是 Android 中用于高效展示大量列表项的组件。通过配合 ItemTouchHelper 工具类,可以轻松实现列表项的拖拽(Drag)与滑动删除或移除(Swipe)功能,无需依赖第三方库。
基础
ItemTouchHelper 与 ItemTouchHelper.Callback
1. 支持拖动与滑动
结合 ItemTouchHelper,可以通过配置拖动方向和滑动方向,实现上下拖动、左右滑动等交互。
2. 实现接口方法
public abstract int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder);
- 指定哪些动作可被支持(拖动上下、滑动左右等),通常使用 makeMovementFlags() 来构建
public abstract boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target);
- 响应拖拽,将项从一个位置移动到另一个位置,需要更新数据源并调用 notifyItemMoved()
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);
- 响应滑动,执行例如删除项的操作,并调用 notifyItemRemoved()
3. 与 Adapter 解耦
通常设计一个接口,例如 ItemTouchHelperAdapter,包含 onItemMove(…) 与 onItemDismiss(…),由 RecyclerView 的 Adapter 实现数据更新逻辑
4. 绑定 ItemTouchHelper
ItemTouchHelper.Callback callback = new MyItemTouchHelperCallback(adapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(recyclerView);
进阶
此部分主要探讨如何为拖拽增加手柄(handle)、在网格布局中运用拖拽,以及添加自定义动画。
1. 拖拽手柄
如果希望只有在特定 View(如一个“拖动图标”)被按住时才启动拖拽,则需要调用 ItemTouchHelper.startDrag(ViewHolder),而不是开启长按即拖
2. 支持网格布局
在使用 GridLayoutManager 或 StaggeredGridLayoutManager 时,你可以按行列方向配置允许拖动的方向
3. 自定义动画和视觉反馈
- 重写 onSelectedChanged() 和 clearView() 来在拖拽开始与结束时修改选中项的视觉(如背景色变更等)
- 配合 ItemAnimator 可实现平滑位移动画
封装实现
定义触控回调
class MyItemTouchHelperCallback(private val adapter: ItemTouchHelperAdapter? = null) :ItemTouchHelper.Callback() {override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {// 支持向上向下拖拽,向左滑动val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWNval swipeFlags = ItemTouchHelper.START // 或 ENDreturn makeMovementFlags(dragFlags, swipeFlags)}override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder): Boolean {adapter.onItemMove(viewHolder.bindingAdapterPosition, target.bindingAdapterPosition);return true;}override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {adapter.onItemDismiss(viewHolder.bindingAdapterPosition);}override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?