Android recyclerview源码分析(二)

    xiaoxiao2021-04-19  128

    这篇文章分析这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里面所做的事情

    转载请注明原文地址: https://ju.6miu.com/read-676071.html

    最新回复(0)