考虑一个场景 ViewPager 嵌套 ViewPager,不做任何处理的情况下,正常滑动非边界区域,默认会滑动内层 ViewPager。
那么问题来了,讲道理事件分发会先走「外层 ViewPager」 的 onInterceptTouchEvent,内外都是 ViewPager,代码都一样。
怎么事件没有被「外层 ViewPager」拦截掉,反而交给了「内层 ViewPager」呢?
更多问答 >>
-
每日一问 很多书籍上写:“事件分发只有一次 ACTION_DOWN,一次 ACTION_UP”严谨吗?
2020-01-07 00:08 -
每日一问 为什么 Dialog 默认弹出后 Activity 就无法响应用户事件了?
2020-01-15 19:24 -
每日一问 据说很多 app 在 2019 年最后一周都出现了日期上的 bug ?
2020-01-14 20:33 -
每日一问 系统帮我们做了网络安全校验,那么还需要我们手动去做吗?
2020-01-14 20:33 -
每日一问 “别慌,你 post 一个 Runnable ,在下一帧就可以拿到了。”这种说法对吗?
2020-01-20 01:05 -
每日一问 Activity 都重建了,你 Fragment凭什么活着?
2019-12-23 23:19 -
2019-12-20 00:08
-
2019-12-15 23:55
-
每日一问 Android 签名机制 v1 v2 v3 , 卧槽都 v3 了?
2019-12-09 23:52 -
2019-12-04 00:18

ViewPager 事件处理
ViewPager.onInterceptTouchEvent
该方法主要计算是否拦截滑动事件变量:mIsBeingDragged,满足下面2个主要条件才拦截:MotionEvent.ACTION_MOVE中canScroll方法:
canScroll源码:
从参数说明中就很容易知道,如果子view可以滑动,返回为true
ViewPager.onTouchEvent
该方法主要是通过上面计算出的mIsBeingDragged变量,判断是否需要滑动操作,在不同MotionEvent中处理的内容:赞同 @funnydsx 同学的回答。
补充一个canScroll方法的源码解析:可以看出这个方法是一个递归方法,它会先检查传进来的View是不是ViewGroup,如果是的话,就会把【符合条件的子View】继续扔进
canScroll方法中。注意这时候参数checkV传的是true,表示这次要连这个View本身也一起检测,而非只检测它的子View。符合条件的子View是指哪些呢?
即当前触摸的坐标点,在子View的边界范围内。可以看到它会先加上ScrollX或ScrollY,就是为了触摸坐标能对齐到滚动后的View。接着看最后一行,如果
参数checkV为true的话,会调用v(也就是传进来的那个子View)的canScrollHorizontally方法,并将 负的dx传了进去。dx就是手指本次水平滑动的距离,如果是向右滑动的话,那么这个值就会是正数,向左滑则负数。好,来看看
canScrollHorizontally的代码:先看后面的判断逻辑,如果是向右滑动(
direction< 0),则判断offset是否 > 0,来看看offset是怎么来的:它是直接返回了ScrollX的值,也就是说,如果手指是向右滑动的话,就看这个View之前有没有向左边滚动过,有的话,就表示可以向右滚动(返回true)。
如果手指是向左滑动,则判断
offset(也就是ScrollX)是否小于【range- 1】,range的值可以看到是用computeHorizontalScrollRange方法的返回值 减去computeHorizontalScrollExtent的返回值,看看这两个方法:emmm,返回的都是该View的宽度,那
向左滑动的话,参数range的值就是0了。direction会是正数,不可能会小于 -1了,所以这时候会返回true。很赞,不过关于 canScrollHorizontally 的分析,具体需要考虑子View的实际类型。上述提到的方法源码都是View的源码逻辑。比如:ViewPager自身就重写了 canScroll ...查看更多
很赞,不过关于 canScrollHorizontally 的分析,具体需要考虑子View的实际类型。上述提到的方法源码都是View的源码逻辑。比如:ViewPager自身就重写了 canScrollHorizontally 。
棒,解开了我对canScrollHorizontally的疑惑,两位回答都很精彩
想问一下,ViewPager 嵌套在 ViewPager2 里,为什么 ViewPager 的左右滑动事件就被 ViewPager2 拦截了?
if (range == 0) return false; 怎么解释, final int range = computeHorizontalScrollRange() - computeHorizo ...查看更多
if (range == 0) return false; 怎么解释, final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 应该是等于0的
是昨天这个文章吗?
重学安卓:学习 View 事件分发,就像外地人上了黑车!不是哈
因为子viewPager 能抢占父viewPager 的焦点, 所以先滑动的是子viewPager
再补充1个 @00后小花旦 的回答
canScrollHorizontally的解释有误,按照00后小花旦的解释
代码中range == 0恒成立,实际跑了下也是,那就一直返回false了?
其实viewpager重载了canScrollHorizontally方法
mFirstOffset = 0,mLastOffset viewpager的length
假设viewpager的length=4,vieapager充满屏幕=1080向右滑动(direction < 0)
向左滑动 (direction > 0)
当viewpager处在第一个时,scrollX=0,向右滑动,direction < 0,(scrollX > (int) (width mFirstOffset));返回false,向左滑动,direction > 0,(scrollX < (int) (width mLastOffset)); 返回true
viewpager处在最后一个时,scrollX = width * mLastOffset,向右滑动,返回false,向左滑动,返回ture