【View系列】手把手教你解决ViewPager2滑动冲突

本文分析了ViewPager2与RecyclerView滑动冲突的常见场景,讲解了RecyclerView的onInterceptTouchEvent和dispatchTouchEvent事件分发流程,提供了解决ViewPager2嵌套RecyclerView滑动冲突的通用方案,包括使用NestedScrollableHost和自定义事件分发策略,帮助开发者理解并解决Android移动开发中的滑动交互问题。
摘要由CSDN通过智能技术生成

常见场景浅析

为了方便大家更好的吸收本篇博客的知识,先描述一个常见场景帮大家理一理事件分发流程。这个场景大家肯定有见过:给RecyclerView的Item设置一个点击事件,点击这个Item通常会有两种情形:

  1. 快速点击,直接触发Item的点击事件
  2. 手指按到这个Item然后开始滑动,这个时候RecyclerView跟着手指开始滑动了

场景1 我们可以简单理解为:快速点击的时候,由于Item设置有点击事件,导致View的onTouchEvent默认返回true,然后滑动距离又小于设备的scaledTouchSlop(最小滑动距离),所以触发了点击事件。

场景2 我们手指按下去的时候,明明ItemView在ACTION_DOWN的时候已经把事件消费了(返回了true),后面的事件流程又是什么样的呢?这个时候我们猜测:刚开始ACTION_DOWN事件是传递给了ItemView,后续的ACTION_MOVE事件,由于滑动距离大于了scaledTouchSlop(最小滑动距离), RecyelerView又将事件拦截下来了,接着后续事件就交由RecyclerView来处理了。为了印证我们的猜测,老规矩还是从源码中找答案,首先我们分析下RecyclerView的onInterceptTouchEvent方法

//RecyclerView.java

...
//0  
private int mScrollState = SCROLL_STATE_IDLE;
...
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
   ...
   //1  
   final boolean canScrollHorizontally = mLayout.canScrollHorizontally();
   final boolean canScrollVertically = mLayout.canScrollVertically();
   ...

   switch (action) {
       ...
       case MotionEvent.ACTION_MOVE: {
               	...
                final int x = (int) (e.getX(index) + 0.5f);
                final int y = (int) (e.getY(index) + 0.5f);
         				//2
                if (mScrollState != SCROLL_STATE_DRAGGING) {
                    final int dx = x - mInitialTouchX;
                    final int dy = y - mInitialTouchY;
                    boolean startScroll = false;
                  	//2
                    if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) {
                        mLastTouchX = x;
                        startScroll = true;
                    }
                    //3
                    if (canScrollVertically && Math.abs(dy) > mTouchSlop) {
                        mLastTouchY = y;
                        startScroll = true;
                    }
                  	//4
                    if (startScroll) {
                        setScrollState(SCROLL_STATE_DRAGGING);
                    }
                }
            } break;
       ...
   }
   //5
   return mScrollState == SCROLL_STATE_DRAGGING;
}
复制代码

下面我们整理一下上面代码的逻辑:

  • 标注5处的代码是onInterceptTouchEvent的返回值,由于mScrollState初始值是SCROLL_STATE_IDLE,所以我们可以得知RecyclerView在接受到ACTION_DOWN事件的时候并没有拦截事件(这是一句废话,如果ACTION_DOWN事件都拦截的话,那么所有自己的子view都拿不到触摸事件了),这也是为啥ACTION_DOWN的时候ItemVi
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值