这篇文章分析这3个类
这3个类是和列表item的drag和swipe手势有关的类,通过这3个类可实现类似dragsortlistview的功能。
先看下用法
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); mItemTouchHelper = new ItemTouchHelper(callback); mItemTouchHelper.attachToRecyclerView(recyclerView);附上高手写的demo链接
https://github.com/iPaulPro/Android-ItemTouchHelper-Demo其中SimpleItemTouchHelperCallback是继承ItemTouchHelper.Callback
那我们从attachToRecyclerView这个方法开始分析
public void attachToRecyclerView(RecyclerView recyclerView) { if (mRecyclerView == recyclerView) { return; // nothing to do } if (mRecyclerView != null) { destroyCallbacks(); } mRecyclerView = recyclerView; if (mRecyclerView != null) { setupCallbacks(); } } 最后是调用setupCallbacks进行一些初始化工作
private void setupCallbacks() { ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext()); mSlop = vc.getScaledTouchSlop(); mRecyclerView.addItemDecoration(this);//增加ItemDecoration监听 mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);//item swipe手势监听 mRecyclerView.addOnChildAttachStateChangeListener(this);//子view attach和dettach的监听 initGestureDetector();//初始化drag手势监听 }
一、初始化这些监听和ItemTouchHelper内部的一个类息息相关,那就是ItemTouchHelper.Callback,这个Callback
1.初始化sUICallback
static { if (Build.VERSION.SDK_INT >= 21) { sUICallback = new ItemTouchUIUtilImpl.Lollipop(); } else if (Build.VERSION.SDK_INT >= 11) { sUICallback = new ItemTouchUIUtilImpl.Honeycomb(); } else { sUICallback = new ItemTouchUIUtilImpl.Gingerbread(); } }ItemTouchUIUtilImpl主要有一下这些方法
1.1onDraw 设置 view 的x、y轴的偏移量
1.2onSelected 不同的系统对应不同的实现
1.3clearView 则是清除 onDraw 、onSelected 做的事情
2.设置哪些类型的手势是enabled
例如:
isItemViewSwipeEnabled 是否可以swipe操作 isLongPressDragEnabled 是否可以drag操作
可以继承ItemTouchHelper.Callback复写这两个方法控制这两个手势是否enable
3.控制drag和swipe手势的方向,例如上下的是drag行为,左右的是swipe行为
getMovementFlags 子类重写,控制每个手势的方向
makeMovementFlags 在一个int值上保存两个手势相关的值,类似android view绘制中makemesure方法
4.当子view被drag时,有两个方法相关
4.1会回调onMove方法,不过是个空实现
4.2当onMove返回true时,会回调onMoved,这个方法能确保被drag的view不会离开recyclerview的边界
5.控制哪些子view可以拖动
5.1canDropOver 空实现
5.2chooseDropTarget 这个方法主要是判断被drag的view应不应该替换被覆盖的那个view,他们俩是否该交换位置
6.当子view处在swipe手势之后
6.1onSwiped 是个空实现,使用者重写可以对adapter的数据进行操作
二、mOnItemTouchListener
这个监听是用来分发drag和swipe事件的
2.1mOnItemTouchListener中 mGestureDetector.onTouchEvent(event); 这句代码是将事件传递给ItemTouchHelperGestureListener.onLongPress()方法
在初始化的时候这个方法就是drag的监听
private void initGestureDetector() { if (mGestureDetector != null) { return; } mGestureDetector = new GestureDetectorCompat(mRecyclerView.getContext(), new ItemTouchHelperGestureListener()); }2.2
if (index >= 0) { checkSelectForSwipe(action, event, index); } 这段代码就是分发swipe事件的
三、真正执行drag和swipe手势的方法
其实无论drag是swipe,最后都要经过select方法,只不过传的参数不同
1.drag
select(viewHolder, ACTION_STATE_DRAG);
2.swipe
select(vh, ACTION_STATE_SWIPE);
那接下来分析下select方法里做了啥
关键代码这一句
mRecyclerView.invalidate(); 调用这句代码后会通知RecyclerView 的OnDraw方法@Override public void onDraw(Canvas c) { super.onDraw(c); final int count = mItemDecorations.size(); for (int i = 0; i < count; i++) { mItemDecorations.get(i).onDraw(c, this, mState); } }
最后还是会CallBack里的onDraw方法
最后总结一下select方法的调用流程,
ItemTouchHelperGestureListener.onLongPress-->select-->Callback.onDraw-->Callback.onChildDraw-->ItemTouchUIUtilImpl.onDraw
select方法其实只是控制了子view的一个偏移位置 ,Callback里的其他方法也有各自调用的时机。看Callback方法说明对应的去看就能理顺ItemTouchHelper里面所做的事情