0x000 前言
现在几乎养成了一种固定的写作模式 , 在开始正文之前 ,总想唠嗑几句 , 或技术简介亦或是近来的所思所想 , 都希望有个记录 , 与人分享交流 。这是一个开放的时代 , 我们很幸运的生活在这个时代 , 这么一个开放的时代 , 互联网将世界各地的知识信息传输到我们面前 , 几乎零距离 。然而 , 信息爆炸也成其了我们的不幸 , 每天被各种信息淹没 , 我们如一叶扁舟 , 在信息的大海里 , 如履薄冰 。
0x001 ItemTouchHelper
在 AndroidUI初探③RecyclerView之ItemDecoration中 , 介绍了RecyclerView Item之间怎样处理Style , ItemDecoration给了我们更多的想象 , 我们可以通过getItemOffsets
来设置偏移量 , onDraw
来绘制各种图形 , 可以通过Drawable来打造漂亮的ItemDecoration 。
如果说ItemDecoration是装饰Item的 , 那么ItemTouchHelper就是Item与用户交互的利器 。那么ItemTouchHelper是个什么样的类呢?他会为我们做些什么样的事情 。
ItemTouchHelper简介
源码中的解释是这样的 :
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
大致说的是:这是一个RecyclerView的工具,提供了drag & swipe 的功能,也就是说 , 这个类可以帮助我们处理RecyclerView中Item的Drag和Swipe
It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.
大致说的是:他需要RecyclerView 还有ItemTouchHelper.CallBack配合使用,可以配置交互类型 , 并可以接收用户操作的事件 。也就是说 , 将ItemTouchHelper与RecyclerView关联之后 , CallBack可以接收到用户操作RecyclerView的事件 , 这样我们就可以做一些交互处理 。
英语渣渣 , 英语好的请忽略翻译
0x002 ItemTouchHelper的使用
一 , 创建ItemHelper对象
// 创建ItemTouchHelper的时候 , 就会要求我们传入CallBack , 用作RecyclerView事件的回调 , 并做出处理 。
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callBack);
// 关联RecylerView
itemTouchHelper.attachToRecyclerView(rvSimpleList);
二 , 实现CallBack
class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
/**
* 需要处理的方向 , 如上下移动 , 左右滑动等
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
return 0;
}
/**
* 移动时会回调
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
/**
* 滑动时会回调
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
}
只需两步 , 我们就可以将RecyclerView的事件接收掉 。那么他是怎么接收的呢 ? 我们深入源码看一看 。
0x003 ItemTouchHelper源码简析
在分析源码的时候 , 通常源码都会比较多 , 所以我们要找准主旨 , 我们是要分析ItemHelper是怎样将RecyclerView的事件接收起来的,那么我们主要看RecyclerView的事件处理,在ItemTouchHelper中是怎样体现的。
首先 , 从ItemTouchHelper关联RecyclerView方法看起 , attachToRecyclerView(@Nullable RecyclerView recyclerView)
这样方法就是我们ItemTouchHelper关联RecyclerView的开始 。
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
if (mRecyclerView == recyclerView) {
return; // nothing to do
}
if (mRecyclerView != null) {
destroyCallbacks();
}
mRecyclerView = recyclerView;
if (mRecyclerView != null) {
final Resources resources = recyclerView.getResources();
mSwipeEscapeVelocity = resources
.getDimension(R.dimen.item_touch_helper_swipe_escape_velocity);
mMaxSwipeVelocity = resources
.getDimension(R.dimen.item_touch_helper_swipe_escape_max_velocity);
setupCallbacks();
}
}
得到了RecyclerView对象 , 接着就是将RecyclerView的TouchListener给抢过来 。进入setupCallbacks()
我们可以看到 , 在ItemTouchHelper中设置的了RecyclerView的addOnItemTouchListener
并且@Override
了onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event)
and onTouchEvent(RecyclerView recyclerView, MotionEvent event)
and onRequestDisallowInterceptTouchEvent(boolean disallowIntercept)
.
onInterceptTouchEvent
和onTouchEvent
主要是将RecyclerView的TouchListener事件传递给ItemTouchHelper.Callback并做了相应的处理, 这样我们就可以在ItemTouchHelper的CallBack只关心我们想要处理的 。
事件传递代码块
if (mSelected == null) {
final RecoverAnimation animation = findAnimation(event);
if (animation != null) {
mInitialTouchX -= animation.mX;
mInitialTouchY -= animation.mY;
endRecoverAnimation(animation.mViewHolder, true);
if (mPendingCleanup.remove(animation.mViewHolder.itemView)) {
// 事件传递
mCallback.clearView(mRecyclerView, animation.mViewHolder);
}
// 主要交互处理
select(animation.mViewHolder, animation.mActionState);
updateDxDy(event, mSelectedFlags, 0);
}
}
0x004 ItemTouchHelper简单示例
public class DragItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ViewHolderDragSwipeItemListener dragSwipeItemListener;
public DragItemTouchHelperCallback(ViewHolderDragSwipeItemListener dragSwipeItemListener) {
this.dragSwipeItemListener = dragSwipeItemListener;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
/*拖拽方向*/
int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
/*滑动方向*/
int swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
int flags = makeMovementFlags(dragFlag, swipeFlag);
return flags;
}
/**
* 是否开启长按拖拽 ,必须开启
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 上下移动交换Item
* @param recyclerView
* @param viewHolder
* @param target
* @return
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
if (dragSwipeItemListener != null) {
dragSwipeItemListener.onDragMoveSwap(viewHolder.getAdapterPosition(),target.getAdapterPosition());
}
return true;
}
/**
* 左右滑动删除
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
if (dragSwipeItemListener != null) {
dragSwipeItemListener.onSwipeDelete(viewHolder.getAdapterPosition());
}
}
/**
* 选中Item状态
* @param viewHolder
* @param actionState Item状态
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
return;
}
viewHolder.itemView.setBackgroundColor(Color.GRAY);
super.onSelectedChanged(viewHolder, actionState);
}
/**
* ItemView复位回调
* @param recyclerView
* @param viewHolder
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setBackgroundColor(Color.WHITE);
// Item会复用 , 所有操作ItemView的状态之后一定要复原
viewHolder.itemView.setAlpha(1);
viewHolder.itemView.setScaleX(1);
viewHolder.itemView.setScaleY(1);
}
/**
* 操作Item的时候会不断调用绘制Item , 我们可以在这里做很多事情。
* @param c
* @param recyclerView
* @param viewHolder
* @param dX
* @param dY
* @param actionState
* @param isCurrentlyActive
*/
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
float value = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(value);
viewHolder.itemView.setScaleX(value);
viewHolder.itemView.setScaleY(value);
}
}
}
0x005 效果图
0x006 The end
高手 , 都是通过不断的练习 。虽然有些事物看起简单 , 但深入其中 ,自会发现 , 每一件事都不是独立而存在 , 都是一环扣着一环 , 不要被表象迷惑 , 要敢于深究其理 。
源码 : AdvancedUI