RecyclerView经常需要添加拖拽、滑动删除的功能,这里在前文的基础上,自定义一个适配器
继承前文的BaseRecyclerViewAdapter,拓展拖拽排序、滑动删除的功能
public abstract class BaseItemRecyclerViewAdapter extends BaseRecyclerViewAdapter{
private int Tag = R.id.BaseQuickAdapter_dragging_support;
private static final int NO_TOGGLE_VIEW = 0;
protected int mToggleViewId = NO_TOGGLE_VIEW;
protected ItemTouchHelper mItemTouchHelper;
protected boolean itemDragEnabled = false;
protected boolean itemSwipeEnabled = false;
protected OnItemDragListener mOnItemDragListener;
protected OnItemSwipeListener mOnItemSwipeListener;
protected boolean mDragOnLongPress = true;
protected View.OnTouchListener mOnToggleViewTouchListener;
protected View.OnLongClickListener mOnToggleViewLongClickListener;
private static final String ERROR_NOT_SAME_ITEMTOUCHHELPER = "Item drag and item swipe should pass the same ItemTouchHelper";
public BaseItemRecyclerViewAdapter(int layoutResId, List data) {
super(layoutResId, data);
}
/**
* To bind different types of holder and solve different the bind events
*
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(K holder, int position) {
super.onBindViewHolder(holder, position);
int viewType = holder.getItemViewType();
if (mItemTouchHelper != null && itemDragEnabled) {
if (mToggleViewId != NO_TOGGLE_VIEW) {
View toggleView = holder.getView(mToggleViewId);
if (toggleView != null) {
toggleView.setTag(Tag, holder);
if (mDragOnLongPress) {
toggleView.setOnLongClickListener(mOnToggleViewLongClickListener);
} else {
toggleView.setOnTouchListener(mOnToggleViewTouchListener);
}
}
} else {
holder.itemView.setTag(Tag, holder);
holder.itemView.setOnLongClickListener(mOnToggleViewLongClickListener);
}
}
}
/**
* 设置长按mToggleViewId触发拖动事件
* 如果未设置mToggleViewId,则在长按item时触发拖动事件
*
* @param toggleViewId the toggle view's id
*/
public void setToggleViewId(int toggleViewId) {
mToggleViewId = toggleViewId;
}
/**
* 如果为true,则拖动事件将在长按时触发,否则将在点击时触发。
*
* @param longPress 默认为true
*/
public void setToggleDragOnLongPress(boolean longPress) {
mDragOnLongPress = longPress;
if (mDragOnLongPress) {
mOnToggleViewTouchListener = null;
mOnToggleViewLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mItemTouchHelper != null && itemDragEnabled) {
mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(Tag));
}
return true;
}
};
} else {
mOnToggleViewTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN
&& !mDragOnLongPress) {
if (mItemTouchHelper != null && itemDragEnabled) {
mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(Tag));
}
return true;
} else {
return false;
}
}
};
mOnToggleViewLongClickListener = null;
}
}
/**
* 开启拖动item功能
* 长按时使用 itemView 作为toggleView。
*
* @param itemTouchHelper {@link ItemTouchHelper}
*/
public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper) {
enableDragItem(itemTouchHelper, NO_TOGGLE_VIEW, true);
}
/**
* 开启拖动item的子view的功能
* 长按时使用传入的 toggleViewId 作为toggleView。
* @param itemTouchHelper {@link ItemTouchHelper}
* @param toggleViewId 被拖动的itemView的子view的id
* @param dragOnLongPress 如果为true,则拖动事件将在长按时触发,否则将在点击时触发。
*/
public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper, int toggleViewId, boolean dragOnLongPress) {
itemDragEnabled = true;
mItemTouchHelper = itemTouchHelper;
setToggleViewId(toggleViewId);
setToggleDragOnLongPress(dragOnLongPress);
}
/**
* 禁用拖动item功能
*/
public void disableDragItem() {
itemDragEnabled = false;
mItemTouchHelper = null;
}
public boolean isItemDraggable() {
return itemDragEnabled;
}
/**
* 启用滑动item功能
*/
public void enableSwipeItem() {
itemSwipeEnabled = true;
}
public void disableSwipeItem() {
itemSwipeEnabled = false;
}
public boolean isItemSwipeEnable() {
return itemSwipeEnabled;
}
/**
* 拖动接口
*/
public interface OnItemDragListener {
void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos);
void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to);
void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos);
}
/**
* 拖动事件,在Activity中调用mAdapter.setOnItemDragListener(onItemDragListener)
* @param onItemDragListener 拖动事件的回调。
*/
public void setOnItemDragListener(OnItemDragListener onItemDragListener) {
mOnItemDragListener = onItemDragListener;
}
public int getViewHolderPosition(RecyclerView.ViewHolder viewHolder) {
return viewHolder.getAdapterPosition();
}
/**
* 拖动开始
* @param viewHolder
*/
public void onItemDragStart(RecyclerView.ViewHolder viewHolder) {
if (mOnItemDragListener != null && itemDragEnabled) {
mOnItemDragListener.onItemDragStart(viewHolder, getViewHolderPosition(viewHolder));
}
}
/**
* 拖动中
* @param source
* @param target
*/
public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
int from = getViewHolderPosition(source);
int to = getViewHolderPosition(target);
if (inRange(from) && inRange(to)) {
if (from < to) {
for (int i = from; i < to; i++) {
Collections.swap(data, i, i + 1);
}
} else {
for (int i = from; i > to; i--) {
Collections.swap(data, i, i - 1);
}
}
notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition());
}
if (mOnItemDragListener != null && itemDragEnabled) {
mOnItemDragListener.onItemDragMoving(source, from, target, to);
}
}
/**
* 拖动结束
* @param viewHolder
*/
public void onItemDragEnd(RecyclerView.ViewHolder viewHolder) {
if (mOnItemDragListener != null && itemDragEnabled) {
mOnItemDragListener.onItemDragEnd(viewHolder, getViewHolderPosition(viewHolder));
}
}
/**
* 滑动接口
*/
public interface OnItemSwipeListener {
void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos);
/**
* 如果在onItemSwipeStart中更改视图
* 该方法要重置
*
* @param pos 如果视图被刷过,则pos将为负数。
*/
void clearView(RecyclerView.ViewHolder viewHolder, int pos);
void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos);
void onItemSwipeMoving(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive);
}
/**
* 滑动事件,在Activity中调用mAdapter.setOnItemSwipeListener(OnItemSwipeListener)
* @param listener 滑动事件的回调
*/
public void setOnItemSwipeListener(OnItemSwipeListener listener) {
mOnItemSwipeListener = listener;
}
/**
* 滑动开始
* @param viewHolder
*/
public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder) {
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.onItemSwipeStart(viewHolder, getViewHolderPosition(viewHolder));
}
}
/**
* 滑动结束
* @param viewHolder
*/
public void onItemSwipeClear(RecyclerView.ViewHolder viewHolder) {
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.clearView(viewHolder, getViewHolderPosition(viewHolder));
}
}
/**
* 滑动刷新项目时调用,视图将从适配器中删除。
* @param viewHolder
*/
public void onItemSwiped(RecyclerView.ViewHolder viewHolder) {
int pos = getViewHolderPosition(viewHolder);
if (inRange(pos)) {
data.remove(pos);
notifyItemRemoved(viewHolder.getAdapterPosition());
}
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.onItemSwiped(viewHolder, getViewHolderPosition(viewHolder));
}
}
/**
* 自定义侧滑删除动画
* @param canvas 空白的画布
* @param viewHolder 正在与用户交互的ViewHolder
* @param dX 侧滑水平位移量
* @param dY 侧滑垂直位移量
* @param isCurrentlyActive
*/
public void onItemSwiping(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive) {
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.onItemSwipeMoving(canvas, viewHolder, dX, dY, isCurrentlyActive);
}
}
private boolean inRange(int position) {
return position >= 0 && position < data.size();
}
}
ItemTouchHelper在RecyclerView的整个体系中,负责监听Item的手势操作,我们通过给它设置一个继承于ItemTouchHelper.Callback的子类,在其中处理Item的UI变化,就可以完成侧滑删除、拖动排序等操作
不了解的可以参考:https://www.jianshu.com/p/0bbc44cc1582
public class BaseItemTouchHelpCallback extends ItemTouchHelper.Callback{
private BaseItemRecyclerViewAdapter mAdapter;
public BaseItemTouchHelpCallback(BaseItemRecyclerViewAdapter mAdapter){
this.mAdapter = mAdapter;
}
/**
* 拖拽方向:上、下、左、右
*/
private int mDragMoveFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
public void setDragMoveFlags(int dragMoveFlags) {
mDragMoveFlags = dragMoveFlags;
}
/**
* 滑动方向:右滑
*/
private int mSwipeMoveFlags = ItemTouchHelper.END;
public void setSwipeMoveFlags(int swipeMoveFlags) {
mSwipeMoveFlags = swipeMoveFlags;
}
/**
* 是否可以通过长按来触发拖动操作,
* @return 默认返回true,如果返回false,那么可以通过startDrag(ViewHolder)方法来触发某个特定Item的拖动的机制
*/
@Override
public boolean isLongPressDragEnabled() {
return false;
}
/**
* 是否启动在任意位置滑动
* @return true:在任意位置发生触摸事件时启用滑动操作
*/
@Override
public boolean isItemViewSwipeEnabled() {
return mAdapter.isItemSwipeEnable();
}
/**
* 拖拽的时候移动多少距离就判定为可以交换了,默认0.5F
*/
private float mMoveThreshold = 0.1f;
public void setMoveThreshold(float moveThreshold) {
mMoveThreshold = moveThreshold;
}
@Override
public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
return mMoveThreshold;
}
/**
* 滑动的时候移动多少距离就判定为可以交换了
*/
private float mSwipeThreshold = 0.7f;
public void setSwipeThreshold(float swipeThreshold) {
mSwipeThreshold = swipeThreshold;
}
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
return mSwipeThreshold;
}
private int Tag = R.id.BaseQuickAdapter_dragging_support;
/**
* 设置拖拽或滑动方向
* 当用户拖拽或者滑动Item的时候需要告诉系统拖拽或者滑动的方向
* @param recyclerView recyclerView
* @param viewHolder 选中的viewHolder
* @return
*/
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(mDragMoveFlags, mSwipeMoveFlags);
}
/**
* 滑动或拖动开始时调用
* @param viewHolder 滑动或拖动的ViewHolder
* @param actionState ViewHolder的状态,ACTION_STATE_DRAG拖拽,ACTION_STATE_SWIPE滑动
*/
@Override
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
if (viewHolder!= null){
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG ) {
mAdapter.onItemDragStart(viewHolder);
// viewHolder.itemView.setTag(Tag, true);
} else if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE ) {
mAdapter.onItemSwipeStart(viewHolder);
// viewHolder.itemView.setTag(Tag, true);
}
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 滑动或拖动结束时调用
* @param recyclerView recyclerView
* @param viewHolder 滑动或拖动的ViewHolder
*/
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if (viewHolder.itemView.getTag(Tag) != null ) {//&& (Boolean) viewHolder.itemView.getTag(Tag)
mAdapter.onItemDragEnd(viewHolder);
// viewHolder.itemView.setTag(Tag, false);
}
if (viewHolder.itemView.getTag(Tag) != null ) {
mAdapter.onItemSwipeClear(viewHolder);
// viewHolder.itemView.setTag(Tag, false);
}
}
/**
* 当Item被拖拽的时候回调
* @param recyclerView recyclerView
* @param source 拖拽的viewHolder
* @param target 目的拖拽viewHolder
* @return true: ViewType相同调用onMoved;设置source.getItemViewType() == target.getItemViewType();不同 ViewType 之间不能进行拖拽
*/
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, @NonNull RecyclerView.ViewHolder target) {
return true;
}
/**
* 当onMove返回true时回调,刷新列表
* @param recyclerView recyclerView
* @param source 拖拽的viewHolder
* @param fromPos
* @param target 目的拖拽viewHolder
* @param toPos
* @param x
* @param y
*/
@Override
public void onMoved(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, int fromPos, @NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
super.onMoved(recyclerView, source, fromPos, target, toPos, x, y);
mAdapter.onItemDragMoving(source, target);
}
/**
* 当Item被滑动的时候回调
* @param viewHolder 要删除的item
* @param direction 表示滑动的方向
*/
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemSwiped(viewHolder);
}
/**
* 自定义侧滑删除动画时
* @param c
* @param recyclerView recyclerView
* @param viewHolder 正在与用户交互的ViewHolder
* @param dX 侧滑水平位移量
* @param dY 侧滑垂直位移量
* @param actionState 状态
* @param isCurrentlyActive
*/
@Override
public void onChildDrawOver(@NotNull Canvas c, @NotNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
View itemView = viewHolder.itemView;
c.save();
if (dX > 0) {
c.clipRect(itemView.getLeft(), itemView.getTop(),
itemView.getLeft() + dX, itemView.getBottom());
c.translate(itemView.getLeft(), itemView.getTop());
} else {
c.clipRect(itemView.getRight() + dX, itemView.getTop(),
itemView.getRight(), itemView.getBottom());
c.translate(itemView.getRight() + dX, itemView.getTop());
}
mAdapter.onItemSwiping(c, viewHolder, dX, dY, isCurrentlyActive);
c.restore();
}
}
}
//拖动or滑动事件回调
val baseItemTouchHelpCallback = BaseItemTouchHelpCallback(mAdapter)
val itemTouchHelper = ItemTouchHelper(baseItemTouchHelpCallback)
itemTouchHelper.attachToRecyclerView(recyclerView)
//开启item拖拽
mAdapter.enableDragItem(itemTouchHelper)
//开启item中子view的拖拽,开启后textView将被占用
//mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true);
//拖拽回调事件,非必要
//mAdapter.setOnItemDragListener(onItemDragListener);
// 开启滑动删除
mAdapter.enableSwipeItem();
//滑动回调事件,非必要
//mAdapter.setOnItemSwipeListener(onItemSwipeListener);