在 Android 开发中,为列表视图添加拖动排序功能可以极大地提升用户体验。本篇文章将详细指导您如何使用 Android 原生提供的 ItemTouchHelper 工具类,结合流行的 BRVAH (BaseRecyclerViewAdapterHelper) 库,实现 RecyclerView 的长按拖动排序功能。
本文将以一个使用 BaseQuickAdapter 的嘉宾列表 PaipaiGuestAdapter 为例进行讲解和代码实现。
一、核心原理与实现步骤
实现 RecyclerView 拖动排序的核心在于使用 ItemTouchHelper。它通过一个回调接口 ItemTouchHelper.Callback 监听用户的手势,并将事件传递给我们的 Adapter 来执行数据操作和 UI 刷新。
关键步骤:
定义接口 (ItemTouchHelperAdapter): 规范 Adapter 的数据移动方法。
实现 Adapter: 在 PaipaiGuestAdapter 中实现数据交换逻辑,并添加拖动时的视觉反馈。
创建 Callback: 编写 SimpleItemTouchHelperCallback,定义拖动方向和手势启用。
绑定: 在 Activity/Fragment 中将 ItemTouchHelper 附加到 RecyclerView。
二、代码实现
- 步骤一:定义数据移动接口 (ItemTouchHelperAdapter.java)
这个接口是 ItemTouchHelper.Callback 与 Adapter 之间沟通的桥梁。
package com.bgzb.bingganbgzb.ui.room.main.paipai.adapter;
public interface ItemTouchHelperAdapter {
void onItemMove(int fromPosition, int toPosition); }
|
- 步骤二:修改 Adapter (PaipaiGuestAdapter.java)
我们让 PaipaiGuestAdapter 实现 ItemTouchHelperAdapter,并处理拖动过程中的数据交换和视觉反馈。
注意: 为了解决 Inconvertible types 的编译问题,我们在 onItemSelected 和 onItemClear 中使用了 RecyclerView.ViewHolder 作为参数,并配合 @SuppressWarnings(“unchecked”) 进行安全转换。
package com.bgzb.bingganbgzb.ui.room.main.paipai.adapter;
import android.graphics.Color; import android.view.View;
import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder;
import java.util.Collections; import java.util.List;
public class PaipaiGuestAdapter extends BaseQuickAdapter<GuestItem, BaseDataBindingHolder<UserItemBinding>> implements ItemTouchHelperAdapter {
@Override public void onItemMove(int fromPosition, int toPosition) { List<GuestItem> list = getData(); Collections.swap(list, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
}
@SuppressWarnings("unchecked") public void onItemSelected(RecyclerView.ViewHolder viewHolder) { if (viewHolder instanceof BaseDataBindingHolder) { BaseDataBindingHolder<UserItemBinding> holder = (BaseDataBindingHolder<UserItemBinding>) viewHolder; if (holder.getDataBinding() != null) { holder.getDataBinding().bg.setBackgroundColor(Color.LTGRAY); } } }
@SuppressWarnings("unchecked") public void onItemClear(RecyclerView.ViewHolder viewHolder) { if (viewHolder instanceof BaseDataBindingHolder) { BaseDataBindingHolder<UserItemBinding> holder = (BaseDataBindingHolder<UserItemBinding>) viewHolder;
int position = viewHolder.getAdapterPosition();
if (position == RecyclerView.NO_POSITION || position >= getData().size() || position < 0) { return; }
if (holder.getDataBinding() != null) { GuestItem item = getData().get(position); if (setListType == 2) { if (item.getUser_id().equals(UserManager.INSTANCE.getUserDto().user_id)) { holder.getDataBinding().bg.setBackgroundResource(R.drawable.guest_list_mine_bg); holder.getDataBinding().bg.setBackgroundColor(Color.parseColor("#00000000")); } else { holder.getDataBinding().bg.setBackgroundColor(Color.parseColor("#80FFFFFF")); holder.getDataBinding().bg.setBackgroundResource(0); } } else { holder.getDataBinding().bg.setBackgroundColor(Color.TRANSPARENT); holder.getDataBinding().bg.setBackgroundResource(0); } } } }
@Override protected void convert(@NonNull BaseDataBindingHolder<UserItemBinding> userItemBindingBaseDataBindingHolder, GuestItem guestItem) { userItemBindingBaseDataBindingHolder.getDataBinding().num.setText( String.valueOf(userItemBindingBaseDataBindingHolder.getAdapterPosition() + 1) ); } }
|
- 步骤三:创建 Callback (SimpleItemTouchHelperCallback.java)
这是定义手势行为的类,它将长按事件转换为拖动事件,并调用 Adapter 的方法。
package com.bgzb.bingganbgzb.ui.room.main.paipai.adapter;
import androidx.annotation.NonNull; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView;
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final PaipaiGuestAdapter mAdapter;
public SimpleItemTouchHelperCallback(PaipaiGuestAdapter adapter) { mAdapter = adapter; }
@Override public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; final int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); }
@Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return true; }
@Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { } @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && viewHolder != null) { mAdapter.onItemSelected(viewHolder); } super.onSelectedChanged(viewHolder, actionState); }
@Override public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); mAdapter.onItemClear(viewHolder); }
}
|
- 步骤四:在 Activity/Fragment 中绑定
最后,在您的 Activity 或 Fragment 初始化 RecyclerView 的地方添加以下几行代码来启用拖动功能。
val recyclerView = view.findViewById<RecyclerView>(R.id.user_list) val paipaiGuestAdapter = PaipaiGuestAdapter() recyclerView.adapter = paipaiGuestAdapter
val callback = SimpleItemTouchHelperCallback(paipaiGuestAdapter)
val itemTouchHelper = ItemTouchHelper(callback)
itemTouchHelper.attachToRecyclerView(recyclerView)
|
注意: itemTouchHelper 请只实例化和使用一次!刷新和替换数据直接setList即可