[入门向]关于RecyclerView的事件拦截机制

本文详细分析了RecyclerView在处理触摸事件时的拦截机制,解释了ACTION_DOWN、ACTION_MOVE和ACTION_UP如何被处理,并探讨了RecyclerView的OnItemTouchListener接口如何实现自定义事件监听。通过源码解析,提出了两种解决子项事件处理问题的方案,帮助开发者更好地理解和定制RecyclerView的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:本文章已独家授权郭霖公众号

目录

一、发现问题

二、原因分析

1、事件分发的机制

2、原因猜测

三、RecyclerView事件拦截机制

switch (action)部分

返回值

ACTION_DOWN

ACTION_MOVE

ACTION_UP

小结

switch (action) 之前

OnItemTouchListener接口

拦截过程

小结

四、解决问题

方案一

方案二

五、总结


一、发现问题

最近在利用RecyclerView做开发的时候,遇到了一点问题:

给RecyclerView的子项添加事件监听的时候,发现ACITON_DOWN能得到处理,ACITON_UPACTION_MOVE却得不到处理。

二、原因分析

在刚开始开发需求的时候我还不太了解事件分发的机制。所以我先去学习了一下事件分发,这里对事件分发做一个简单的总结。

1、事件分发的机制

事件分发是由三个方法配合完成的:

  • dispatchTouchEvent() 分发事件

  • onInterceptTouchEvent() 拦截事件

  • onTouchEvent() 处理事件

而且事件分发的顺序是:

Activity -> ViewGroup -> View

借助一张图来配合理解:

(图源:Android事件分发机制详解:史上最全面、最易懂 - 天涯海角路 - 博客园 (cnblogs.com))

通过图片我们可以看到,ViewGroup是比较特殊的。onInterceptTouchEven()是他独有方法,他可以将事件拦截下来选择不分发给下一层的View而是自己处理。

2、原因猜测

在了解了事件分发的机制过后,我就猜测会不会是因为RecyclerView将事件拦截了下来。因为RecyclerView肯定有他自己的事件监听,当ACTION_MOVE的时候应该会触发滚动,加载数据然后显示到屏幕上。

那如果真的是被RecyclerView给拦截了,那我又产生了新的疑问:

  • 根据事件分发的机制,再ACITON_DOWN的时候应该就决定了targetViewitemView,为什么在ACITON_MOVE的时候会目标View又变成了RecyclerView

  • RecyclerView是怎么做到只拦截ACTION_MOVEACTION_UP而不拦截ACTION_DOWN的呢?

  • 那如果想要实现子项自己处理ACTION_MOVEACTION_UP要怎么处理呢?

为了验证我的猜想解决这些疑问,我决定去RecyclerView的源码里一探究竟。

三、RecyclerView事件拦截机制

既然我们要分析的是拦截机制,那么当然应该去onTouchEvent()这个方法里去看。

这里先说明一下,以下贴出来的源码并不是全部。我一直觉得分析源码不能一行一行的扣,不然思路会很混乱。在这篇文章里,我只把对解决问题有用的部分贴了出来,也能让大家更好理解。如果有小伙伴有看不懂的地方,可以再配合所有源码来理解。

@Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        ...
​
        mInterceptingOnItemTouchListener = null;
        if (findInterceptingOnItemTouchListener(e)) {
            cancelScroll();
            return true;
        }
        
        ...
            
        final int action = e.getActionMasked();
        
        ...
​
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                ...
            } break
                
            ...
                
            case MotionEvent.ACTION_MOVE: {
                ...
            } break;
​
            ...
​
            case MotionEvent.ACTION_UP: {
                ..
            } break;
​
            ...
        }
        return mScrollState == SCROLL_STATE_DRGING;
    }

总的来说这个函数我把他分为两个部分,switch(aciton)之前switch(aciton)部分。我们按倒序分析一下。

switch (action)部分

返回值

这部分呢我们需要先看一下最后的返回值,因为返回值决定了是否拦截。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值