前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android 事件分发】ItemTouchHelper 事件分发源码分析 ( 绑定 RecyclerView )

【Android 事件分发】ItemTouchHelper 事件分发源码分析 ( 绑定 RecyclerView )

作者头像
韩曙亮
发布2023-03-29 14:31:17
3730
发布2023-03-29 14:31:17
举报

Android 事件分发 系列文章目录

【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )

【Android 事件分发】事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 一 )

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 二 )

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 )

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 四 | View 事件传递机制 )

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 )

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 六 )

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 七 )

【Android 事件分发】ItemTouchHelper 简介 ( 拖动/滑动事件 | ItemTouchHelper.Callback 回调 )

【Android 事件分发】ItemTouchHelper 实现侧滑删除 ( 设置滑动方向 | 启用滑动操作 | 滑动距离判定 | 滑动速度判定 | 设置动画时间 | 设置侧滑触发操作 )

【Android 事件分发】ItemTouchHelper 实现拖动排序 ( 设置滑动方向 | 启启用长按拖动功能 | 拖动距离判定 | 设置拖动触发操作 )

【Android 事件分发】ItemTouchHelper 事件分发源码分析 ( 绑定 RecyclerView )


文章目录

一、ItemTouchHelper 事件分发源码分析入口


ItemTouchHelper 使用时 , 是为 ItemTouchHelper 设置一个 RecyclerView 列表 , 不是给 RecyclerView 设置一个 ItemTouchHelper ;

代码语言:javascript
复制
        //4. 添加拖动/滑动事件
        Callback callback = new Callback(adapter);
        mItemTouchHelper = new ItemTouchHelper(callback);
        mItemTouchHelper.attachToRecyclerView(recycler_view);

因此 , 事件分发的核心处理逻辑 , 都在 ItemTouchHelper 中实现 , 要研究其中的事件分发原理 , 主要分析 ItemTouchHelper 中的源码即可 ;

二、ItemTouchHelper 绑定 RecyclerView 源码分析


1、ItemTouchHelper.attachToRecyclerView 方法分析

ItemTouchHelper.attachToRecyclerView 方法 , 用于将 ItemTouchHelper 与 RecyclerView 进行绑定 ; 以该方法为入口 , 进行源码分析 ;

在初始化之前 , 判定该 RecyclerView 是否已经绑定 , 如果已经绑定 , 不再执行该绑定方法 ;

代码语言:javascript
复制
        if (mRecyclerView == recyclerView) {
        	// 判定是否已经绑定 , 如果已经绑定 , 不再执行绑定方法 
            return; // nothing to do
        }

然后清空之前原有的回调 , 其中涉及到 destroyCallbacks 方法 , 该 destroyCallbacks 方法与 setupCallbacks 方法相对应 , 一个是设置 , 一个是销毁 ;

代码语言:javascript
复制
        if (mRecyclerView != null) {
        	// 使用前 , 清空所有的回调 
        	// 使用前重置 
            destroyCallbacks();
        }

最后 , 设置当前的 mRecyclerView 成员为绑定的 RecyclerView 列表 , 并调用 setupCallbacks 方法 , 为 ItemTouchHelper 设置回调 ;

在 setupCallbacks 中 , 调用 RecyclerView.addOnItemTouchListener 方法 , 为 RecyclerView 设置了触摸监听器 , 该触摸监听器是定义在 ItemTouchHelper 中的成员变量 private final OnItemTouchListener mOnItemTouchListener ;

代码语言:javascript
复制
        // 添加了每个条目上的触摸监听器 mOnItemTouchListener 
        // 该监听器是定义在 ItemTouchHelper 中的成员变量 
        mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);

ItemTouchHelper 相关源码 :

代码语言:javascript
复制
public class ItemTouchHelper extends RecyclerView.ItemDecoration
        implements RecyclerView.OnChildAttachStateChangeListener {

	private final OnItemTouchListener mOnItemTouchListener = new OnItemTouchListener() {}

    /**
     * Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already
     * attached to a RecyclerView, it will first detach from the previous one. You can call this
     * method with {@code null} to detach it from the current RecyclerView.
     *
     * @param recyclerView The RecyclerView instance to which you want to add this helper or
     *                     {@code null} if you want to remove ItemTouchHelper from the current
     *                     RecyclerView.
     */
    public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
        if (mRecyclerView == recyclerView) {
        	// 判定是否已经绑定 , 如果已经绑定 , 不再执行绑定方法 
            return; // nothing to do
        }
        if (mRecyclerView != null) {
        	// 使用前 , 清空所有的回调 
        	// 使用前重置 
            destroyCallbacks();
        }
        // 设置当前的 mRecyclerView 成员为绑定的 RecyclerView 列表
        mRecyclerView = recyclerView;
        if (recyclerView != 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);

			// 该方法是核心方法 
			// 为 ItemTouchHelper 绑定 ItemTouchHelper.Callback 
            setupCallbacks();
        }
    }

	// 该方法与 destroyCallbacks 方法相对应
    private void setupCallbacks() {
    	// 配置相关  
        ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext());
        mSlop = vc.getScaledTouchSlop();
        // 设置 RecyclerView 条目中的装饰 , 可以在条目组件 底部 上层 绘制 Canvas 图形 
        // ItemTouchHelper 继承 RecyclerView.ItemDecoration
        mRecyclerView.addItemDecoration(this);
        // 添加了每个条目上的触摸监听器 mOnItemTouchListener 
        // 该监听器是定义在 ItemTouchHelper 中的成员变量 
        mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);
        mRecyclerView.addOnChildAttachStateChangeListener(this);
        startGestureDetection();
    }
	
	// 该方法与 setupCallbacks 方法相对应
	// 清空所有的回调 , 重置 RecyclerView 
    private void destroyCallbacks() {
        mRecyclerView.removeItemDecoration(this);
        mRecyclerView.removeOnItemTouchListener(mOnItemTouchListener);
        mRecyclerView.removeOnChildAttachStateChangeListener(this);
        // clean all attached
        final int recoverAnimSize = mRecoverAnimations.size();
        for (int i = recoverAnimSize - 1; i >= 0; i--) {
            final RecoverAnimation recoverAnimation = mRecoverAnimations.get(0);
            mCallback.clearView(mRecyclerView, recoverAnimation.mViewHolder);
        }
        mRecoverAnimations.clear();
        mOverdrawChild = null;
        mOverdrawChildPosition = -1;
        releaseVelocityTracker();
        stopGestureDetection();
    }
}

2、ItemTouchHelper.setupCallbacks 方法分析

在 ItemTouchHelper.setupCallbacks 方法中 , 调用了

代码语言:javascript
复制
mRecyclerView.addItemDecoration(this);

方法 , 为当前的 RecyclerView 设置条目装饰 , 该装饰可以在条目组件 底部 上层 绘制 Canvas 图形 , 具体的方法如下 :

代码语言:javascript
复制
public class RecyclerView extends ViewGroup implements ScrollingView,
        NestedScrollingChild2, NestedScrollingChild3 {
    /**
     * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can
     * affect both measurement and drawing of individual item views.
     *
     * <p>Item decorations are ordered. Decorations placed earlier in the list will
     * be run/queried/drawn first for their effects on item views. Padding added to views
     * will be nested; a padding added by an earlier decoration will mean further
     * item decorations in the list will be asked to draw/pad within the previous decoration's
     * given area.</p>
     *
     * @param decor Decoration to add
     * @param index Position in the decoration chain to insert this decoration at. If this value
     *              is negative the decoration will be added at the end.
     */
    public void addItemDecoration(@NonNull ItemDecoration decor, int index) {
        if (mLayout != null) {
            mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll  or"
                    + " layout");
        }
        if (mItemDecorations.isEmpty()) {
            setWillNotDraw(false);
        }
        // 将多个 ItemDecoration 添加到 mItemDecorations 集合中
        if (index < 0) {
            mItemDecorations.add(decor);
        } else {
            mItemDecorations.add(index, decor);
        }
        markItemDecorInsetsDirty();
        // 开始进行绘制 
        requestLayout();
    }
}

3、RecyclerView.ItemDecoration 源码分析

ItemDecoration 是抽象类 , 核心逻辑必须由子类实现后才可以使用 ;

void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull State state) 方法是绘制方法 , 在该方法中调用了 void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent) 方法 ,

代码语言:javascript
复制
    public abstract static class ItemDecoration {
        public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull State state) {
            onDraw(c, parent);
        }

        @Deprecated
        public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent) {
        }
    }

参考 Android 官方提供的 RecyclerView.ItemDecoration 的实现类 DividerItemDecoration , 该类中重写了 onDraw 方法 , 其中调用了 drawVertical 绘制垂直分割线 , 调用了 drawHorizontal 方法绘制水平分割线 ;

代码语言:javascript
复制
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (parent.getLayoutManager() == null || mDivider == null) {
            return;
        }
        if (mOrientation == VERTICAL) {
        	// 绘制垂直分割线
            drawVertical(c, parent);
        } else {
        	// 绘制水平分割线
            drawHorizontal(c, parent);
        }
    }
}

在上述 drawVertical 和 drawHorizontal 方法中 , 利用 Canvas 进行绘图 ;

在 RecyclerView.ItemDecoration 中 , 不仅仅只能绘制分割线 , 可以绘制任何图形 , 图片 , 颜色 , 与自定义组件绘制功能一样强大 ;

三、博客资源

博客资源 :

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Android 事件分发 系列文章目录
    • 文章目录
    • 一、ItemTouchHelper 事件分发源码分析入口
    • 二、ItemTouchHelper 绑定 RecyclerView 源码分析
      • 1、ItemTouchHelper.attachToRecyclerView 方法分析
        • 2、ItemTouchHelper.setupCallbacks 方法分析
          • 3、RecyclerView.ItemDecoration 源码分析
          • 三、博客资源
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档