利用 ItemTouchHelper 可以实现 RecyclerView 的侧滑删除和滑动。
在官方文档的定义:
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
要实现 RecyclerView 的侧滑和滑动功能,需要继承 ItemTouchHelper.CallBack 接口,并实现相关方法。不过还好,官方已经为我们实现是一个默认的 CallBack, 叫 ItemTouchHelper.SimpleCallBack;
一、使用 ItemTouchHelper.SimpleCallBack
继承 ItemTouchHelper.SimpleCallBack 需要实现两个方法,
一个是 onMove(RecyclerView, ViewHolder, ViewHolder) ,这是移动时会回调的方法;
另一个是 onSwiped(ViewHolder, int),这是在滑动时的回调方法。
下面是示例代码:
public class SimpleTouchHelper extends ItemTouchHelper.SimpleCallback {
private ItemTouchHelperAdapter mItemTouchHelperAdapter;
public void setItemTouchHelperAdapter(ItemTouchHelperAdapter itemTouchHelperAdapter) {
mItemTouchHelperAdapter = itemTouchHelperAdapter;
}
public SimpleTouchHelper(int dragDirs, int swipeDirs) {
super(dragDirs, swipeDirs);
}
// 移动
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// 移动开始的位置
int formPosition = viewHolder.getAdapterPosition();
//
int toPosition = target.getAdapterPosition();
mItemTouchHelperAdapter.onItemMove(formPosition, toPosition);
return true;
}
// 滑动
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
mItemTouchHelperAdapter.onItemDismiss(position);
}
}
其中 ItemTouchHelperAdapter 是回调接口
public interface ItemTouchHelperAdapter {
void onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
给 RecyclerView 设置 ItemTouchHelper
mSimpleTouchHelper = new SimpleTouchHelper(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT);
mSimpleTouchHelper.setItemTouchHelperAdapter(new ItemTouchHelperAdapter() {
@Override
public void onItemMove(int fromPosition, int toPosition) {
Log.i("swipe", "from position " + fromPosition + " to position " + toPosition);
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(mStringList, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(mStringList, i, i - 1);
}
}
mAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onItemDismiss(int position) {
mStringList.remove(position);
mAdapter.notifyItemRemoved(position);
Toast.makeText(MainActivity.this, "删除 " + position,
Toast.LENGTH_SHORT).show();
}
});
ItemTouchHelper itemTouchHelper = new
ItemTouchHelper(mSimpleTouchHelper);
itemTouchHelper.attachToRecyclerView(recycler_view);
SimpleTouchHelper(int dragDirs, int swipDirs) 构造函数第一个参数是拖动的方法,这里是 UP 和 DOWN 方法,当我们将 item 向上或向下时会是拖动;第二参数是滑动,这里是 LEFT 和 RIGHT, 当将 item 左右时会是滑动。
将 SimpleTouchHelper 作为参数传进 ItemTouchHelper 的构造函数,生成 ItemTouchHelper 对象,然后调用 ItemTouchHelper#attachToRecyclerView(RecyclerView) 发放即可。
在 onItemMove(…) 回调中进行 Item 位置的交换,在 onItemMiss(…) 回调中删除 item.
效果图,滑动删除
效果图,拖动时
二、ItemTouchHelper.CallBack
如果是自定义一个 Touch Callback, 则需要监听拖动和滑动事件。
1.一般需要重写拖动回调 onMove(RecyclerView, ViewHolder, ViewHolder) 事件
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// 开始位置
int fromPosition = viewHolder.getAdapterPosition();
// 拖动的目标位置
int toPosition = target.getAdapterPosition();
mAdapter.onItemMove(fromPosition, toPosition);
// 返回 true, 开启移动
return true;
}
- 重写滑动回调方法 onSwiped(ViewHolder, direction)
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
- 以及 getMovementFlags,onChildDraw 和 onSelectedChanged 方法。
以下是完整代码
public class CustomItemTouchCallBack extends ItemTouchHelper.Callback {
public static final float ALPHA_FULL = 1.0f;
private ItemTouchHelperAdapter mAdapter;
public CustomItemTouchCallBack(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
}
/**
* 控制 行为,并返回一系列的 方向标志
* @param recyclerView
* @param viewHolder
* @return
*/
@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);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// 开始位置
int fromPosition = viewHolder.getAdapterPosition();
// 拖动的目标位置
int toPosition = target.getAdapterPosition();
mAdapter.onItemMove(fromPosition, toPosition);
// 返回 true, 开启移动
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE){ // 滑动的时候
// 当滑动的时候,item 淡出
float alpha = ALPHA_FULL - Math.abs(dX) / viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(alpha);
viewHolder.itemView.setTranslationX(dX);
} else {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
/**
* 选中时 item 的变化
* @param viewHolder
* @param actionState
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE){ // 闲置状态
if (viewHolder instanceof ItemTouchHelperViewHolder){
ItemTouchHelperViewHolder itemTouchHelperViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemTouchHelperViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 释放 item 之前设置的状态
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA_FULL);
Log.i("itemTouch", "clear view");
if (viewHolder instanceof ItemTouchHelperViewHolder){
ItemTouchHelperViewHolder itemTouchHelperViewHolder = (ItemTouchHelperViewHolder) viewHolder;
itemTouchHelperViewHolder.onItemClear();
}
}
/**
* 是否允许长按开始拖动
* 我们这里开启
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 是否选项 item 滑动
* 我们这里开启
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
}
详情,看代码中的注释。
其中 ItemTouchHelperViewHolder 是接口, RecyclerView 中的 ViewHolder 需要实现它。
public interface ItemTouchHelperViewHolder {
/**
* ViewHolder 中 Item 选中时回调
*/
void onItemSelected();
/**
* 完成 移动或者滑动之后的回调,清除 View 的状态
*/
void onItemClear();
}
在 RecyclerView#ViewHolder 中
public class ItemTouchAdapter extends RecyclerView.Adapter<ItemTouchAdapter.VHolder> implements ItemTouchHelperAdapter{
private Context mContext;
private List<String> mStrings;
public ItemTouchAdapter(Context context, List<String> strings) {
mContext = context;
mStrings = strings;
}
@Override
public VHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_layout, parent, false);
return new VHolder(view);
}
@Override
public void onBindViewHolder(VHolder holder, int position) {
holder.tv_item.setText(mStrings.get(position));
}
@Override
public int getItemCount() {
return mStrings.size();
}
@Override
public void onItemMove(int fromPosition, int toPosition) {
Log.i("swipe", "from position " + fromPosition + " to position " + toPosition);
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(mStrings, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(mStrings, i, i - 1);
}
}
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onItemDismiss(int position) {
mStrings.remove(position);
notifyItemRemoved(position);
}
static class VHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder{
TextView tv_item;
public VHolder(View itemView) {
super(itemView);
tv_item = (TextView) itemView.findViewById(R.id.tv_item);
}
@Override
public void onItemSelected() {
itemView.setBackgroundColor(Color.LTGRAY);
}
@Override
public void onItemClear() {
Log.i("itemTouch","onItemClear");
itemView.setBackgroundColor(Color.TRANSPARENT);
}
}
}
最后通过 ItemTouchHelper 设置到 RecyclerView 中
CustomItemTouchCallBack itemTouchCallBack = new CustomItemTouchCallBack(mAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallBack);
itemTouchHelper.attachToRecyclerView(recycler_view);
最后运行的结果与上面的两个图一样的。
从官方文档摘录关于继承 Callback 的几个事项
1. Listen for “move” and “swipe” events.
Can control the state of the view selected, and override the default animations.
To control which actions user can take on each view, override getMovementFlags(RecyclerView, ViewHolder, ViewHolder) and return appropriate set of direction flags(LEFT, RIGHT, START, END, UP, DOWN).
Drag on item, call onMove(RecyclerView, dragged, target)
move the item from the old position , dragged.getAdapterPosition() to new position, target.getAdapterPosition .
Adapter call notifyItemMoved(int, int).When a view is swiped calls onSwiped(ViewHolder, int). At this point, update adapter(e.g remove the item) and call related Adapter#notify event.
注:
参考
1. Drag and Swipe with RecyclerView Part One: Basic ItemTouchHelper Example
2.Drag and Swipe with RecyclerView Part Two: Handles, Grids, and Custom Animations