与滑动冲突的首次邂逅(二)

简介: 如果你是一名Android 新手,那么你很可能没有遇见过滑动冲突,甚至不知道滑动冲突是什么?那是因为你的业务需求可能还不够复杂,作为一名初学者,没有将多种组件结合使用,那自然就没有遇见到滑动冲突了。

问题的解决

在这里,笔者先笼统的告知你,滑动冲突的解决大致分为:外部解决法和内部解决法。而其原理,就是基于前文View体系(上)|青训营笔记 - 掘金 (juejin.cn)中讲到的事件分发机制了。这里我引用其一小段代码简要的说明下其分发机制。

View 的事件分发是,首先 View 层层分发下来,若是 onInterceptTouchEvent(ev)true 就拦截,为 false 就继续下发。

当某一层级拦截后,就调用 onTouchEvent(event) 来处理,若是该层无法处理,就传递给父层的 onTouchEvent(event) 来处理。如此层层传递直到有对应可以处理的父层。

//伪代码
public boolean dispatchTouchEvent(MotionEvent ev){
    boolean result = false;
    if(onInterceptTouchEvent(ev)){
        result = onTouchEvent(ev);
    }else{
        result = child.dispatchTouchEvent(ev);
    }
    return result;
}
复制代码

1.webp.jpg

现在我们再次说回这两种解决方法,其中重写 onInterceptTouchEvent() 方法就是外部解决法,重写 dispatchTouchEvent() 就是内部解决法

我们这里选用的是 内部解决法。在下面的代码中,如果你是小白,那无需很深刻的理解我解决的过程,大致了解即可。

我们分析上面的需求得出,产生冲突的是  ViewpagerNestedScrollView ;而由于我们使用的是  Viewpager2 ,其没有默认解决滑动冲突,且无法继承,所以我们选择使用 NestedScrollView 来解决。所以选用的是  内部解决法

下面给出重写代码:

public class NestedScrollViewVP extends NestedScrollView {
    public NestedScrollViewVP(@NonNull Context context) {
        super(context);
    }
    public NestedScrollViewVP(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public NestedScrollViewVP(@NonNull Context context, @Nullable AttributeSet attrs,
                              int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    private int startX, startY;
    boolean isDisallowIntercept = false;
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = (int) ev.getX();
                startY = (int) ev.getY();
                getParent().requestDisallowInterceptTouchEvent(true);//告诉viewgroup不要去拦截我
                break;
            case MotionEvent.ACTION_MOVE:
                int endX = (int) ev.getX();
                int endY = (int) ev.getY();
                int disX = endX - startX;
                int disY = endY - startY;
                //角度正确,则让上层view别拦截我的事件
                float r = (float)Math.abs(disY)/Math.abs(disX);
                if (r > 0.6f) isDisallowIntercept = true;
                getParent().requestDisallowInterceptTouchEvent(isDisallowIntercept);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                isDisallowIntercept = false;
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}
复制代码

上面的而代码中,我们继承了 NestedScrollView 之后,主要对 dispatchTouchEvent() 方法进行了重写。修改逻辑大致如下

  1. ACTION_DOWN 中,记录手指触发的初始位置,然后请求父View不对事件做拦截,默认先把事件传递给  NestedScrollView
  2. ACTION_MOVE 中,计算当前的位置与初始位置形成的角度,如果它的正切值大于 0.6 则认为这是上下滑动的命令,需要父View不对事件做拦截。
  3. ACTION_UPACTION_CANCEL 中,则请求父View进行事件拦截,让其回到默认的状态。

上面有一点需要注意:在上述的代码中,我们设置了一个变量 isDisallowIntercept记录是否阻止父View拦截事件。这个变量的设置很重要,它达到的效果是记录是否发生纵向滑动;如果有发生纵向滑动就请求父View禁止拦截事件,让事件都交给 NestedScrollView 处理,这样子连续的上下滑动就不会被判断为左右滑动了。

为何不设置这样子一个变量就会被判断为左右滑动呢?请看下图,首次滑动的轨迹1是被判断为纵向滑动的,而轨迹2我们直观上去是纵向滑动,但是实际上系统记录的起点->终点的轨迹是红色轨迹,因为起点是一直不变的,这也就导致了轨迹2被判定为横向滑动。所以我们需要一个变量来记录第一次滑动的方向,以供很好的判断。

这个方法中,我们只需要考虑捕获纵向滑动的事件,让纵向滑动不会被误判为横向滑动就行,而不用考虑横变纵的问题。因为触发横向滑动后,是被父View拦截处理的,一旦父View拦截后,NestedScrollView 中的事件就直接变为 ACTION_CANCEL 类型了,NestedScrollView 中的事件分发方法直接不会被执行了。

所以,经过上述的处理,该页面在每次触点按下之后,只要触点不离开,那么处理事件的布局就不会变化。

1.webp.jpg

最后,我们在布局文件中引用我们的修改的子类即可。

<com.qxy.potatos.module.videorank.myview.NestedScrollViewVP
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
</com.qxy.potatos.module.videorank.myview.NestedScrollViewVP>
复制代码

下面是解决了冲突之后的效果,以及不会出现纵向滑动变成横向滑动的问题了,体验感得到极大的提升。

如上所示,我们完美解决了它的滑动冲突,提高了用户体验。

从本文中,你也学到了何为滑动冲突,且窥探了大致的解决过程。算是初试滑动冲突,实现了从0到1的进步

后续我们会继续讲解滑动冲突的原理以及解决方法,敬请期待


相关文章
|
iOS开发 开发者 异构计算
一台iPhone搞定大作动捕,Epic神器MetaHuman Animator开放下载了
一台iPhone搞定大作动捕,Epic神器MetaHuman Animator开放下载了
215 44
|
Android开发
安卓项目之纸牌游戏之四 游戏规则类
安卓项目之纸牌游戏之四 游戏规则类
80 0
|
JavaScript Go CDN
君子不玩物丧志,亦常以借物调心,网站集成二次元网页小组件(widget)石蒜模拟器,聊以赏玩
传世经典《菜根谭》中有言曰:“徜徉于山林泉石之间,而尘心渐息;夷犹于诗书图画之内,而俗气潜消。故君子虽不玩物丧志,亦常借物调心。”意思是,徜徉在林泉山石之间,能够摒弃杂念,留意诗词歌画之中,可以尽弃俗见。所以说君子虽然不会玩物丧志,也常常要借一些优雅的小物件来调理情绪,二次元网页小组件(widget)就是这样的小物件,功能上无甚大观,却可以博君一晒。
君子不玩物丧志,亦常以借物调心,网站集成二次元网页小组件(widget)石蒜模拟器,聊以赏玩
|
Android开发
与滑动冲突的首次邂逅(一)
如果你是一名Android 新手,那么你很可能没有遇见过滑动冲突,甚至不知道滑动冲突是什么?那是因为你的业务需求可能还不够复杂,作为一名初学者,没有将多种组件结合使用,那自然就没有遇见到滑动冲突了。
与滑动冲突的首次邂逅(一)
|
Java Android开发 Kotlin
Android | 这是一份详细的 EventBus 使用教程 | 牛气冲天新年征文
Android | 这是一份详细的 EventBus 使用教程 | 牛气冲天新年征文
880 0
Android | 这是一份详细的 EventBus 使用教程 | 牛气冲天新年征文
|
SQL 存储 自然语言处理
Android | ContentProvider 筑基篇 | 牛气冲天新年征文
Android | ContentProvider 筑基篇 | 牛气冲天新年征文
113 0
Android | ContentProvider 筑基篇 | 牛气冲天新年征文
HAVE FUN | “飞船计划”活动最新进展
我们有完善的文档和上千人的技术交流群,你的问题完全可以得到解答,和更多热爱技术崇尚开源的小伙伴,一起开启你的开源探索之旅吧~
HAVE FUN | “飞船计划”活动最新进展
autojs之RecycleView抽丝剥茧
作者: 牙叔 使用情景: 解析RecycleView常用方法
354 0
autojs之RecycleView抽丝剥茧
|
缓存 Android开发
聊聊RecyclerView新出的ConcatAdapter如何使用
聊聊RecyclerView新出的ConcatAdapter如何使用
聊聊RecyclerView新出的ConcatAdapter如何使用
|
人工智能 数据可视化 算法
2019图灵奖颁给3D电影奠基者!皮克斯“动画帝国”从他们开启,还顺便带火了GPU
2019图灵奖颁给3D电影奠基者!皮克斯“动画帝国”从他们开启,还顺便带火了GPU
248 0