首页 > 其他分享 >从Android事件分发机制看滑动冲突解决方案

从Android事件分发机制看滑动冲突解决方案

时间:2023-09-21 20:32:34浏览次数:40  
标签:分发 MotionEvent dispatchTouchEvent 控件 ACTION 滑动 Android ev true

事件分发机制从ViewGroup的dispatchTouchEvent入手

public boolean dispatchTouchEvent(MotionEvent ev) {
        ...
        final boolean intercepted;
        if (actionMasked == MotionEvent.ACTION_DOWN
                || mFirstTouchTarget != null) {
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!disallowIntercept) {
                intercepted = onInterceptTouchEvent(ev);
                ev.setAction(action); // restore action in case it was changed
            } 

        } else {
            intercepted = true;
        }
       
        if (!canceled && !intercepted) {                                                                     
          ...                                                   
        TouchTarget predecessor = null;                                                 
        TouchTarget target = mFirstTouchTarget;                                         
        while (target != null) {                                                        
            final TouchTarget next = target.next;                                       
            if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {        
                handled = true;                                                         
            } else {                                                                    
                final boolean cancelChild = resetCancelNextUpFlag(target.child)         
                    || intercepted;                                                 
                if (dispatchTransformedTouchEvent(ev, cancelChild,                      
                        target.child, target.pointerIdBits)) {                          
                    handled = true;                                                     
                }                                                                                                                   
           }   
           ...                                                                                                                     
       }                                                                               
    }                                                                                                                                                                     
}

可以看出,ViewGroup的dispatchTouchEvent,首先调用了自己的onInterceptTouchEvent方法,如果此方法返回true,则会短路后面的逻辑。进入下列逻辑

if (mFirstTouchTarget == null) {
            // No touch targets so treat this as an ordinary view.
            handled = dispatchTransformedTouchEvent(ev, canceled, null,
                    TouchTarget.ALL_POINTER_IDS);
        } 

然后调用

super.dispatchTouchEvent(event);

即View的方法,然后调用ViewGroup的onTouchEvent(event)方法

如果ViewGroup的onInterceptTouchEvent返回false则会调用dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign),最终调用 handled = child.dispatchTouchEvent(event);到这里又是一个循环了

用图表示

从Android事件分发机制看滑动冲突解决方案_事件分发

那么,回到滑动冲突,就简单了。 外部拦截法 需要外部控件重写父类的onInterceptTouchEvent 方法,在其中判断什么时候需要拦截事件由自身处理,什么时候需要放行将事件传给内层控件处理,内部控件不需要做任何处理。伪代码如下:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            if (父容器需要自己处理改事件) {
                return true;//拦截
            } else {
                return false;//不拦截
            }
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            break;
    }
    return super.onInterceptTouchEvent(ev);
}

内部拦截法 这种方式需要结合 requestDisllowInterceptTouchEvent(boolean) 这个方法,外部不拦截的情况下,会调用此方法,在内层控件的重写方法dispatchTouchEvent中,根据逻辑来决定外层控件何时需要拦截事件,何时需要放行。(requestDisllowInterceptTouchEvent 这个方法的作用是-是否允许外层控件拦截事件)伪代码如下:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    switch (ev.getAction()){
        case MotionEvent.ACTION_DOWN:
            getParent().requestDisallowInterceptTouchEvent(true);
            break;
        case MotionEvent.ACTION_MOVE:
            if (父容器需要处理改事件) {
                //允许外层控件拦截事件
                getParent().requestDisallowInterceptTouchEvent(false);
            } else {
                //需要内部控件处理该事件,不允许上层viewGroup拦截
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_UP:
            break;
       default:
           break;
    }
    return super.dispatchTouchEvent(ev);
}

同时,在这种方法下需要在外层控件做下处理:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        return false;
    } else {
        return true;
   }
}

注:调用 getParent().requestDisallowInterceptTouchEvent(true)方法之后,父控件在dispatchTouchEvent的时候会直接将事件传递到子控件中

标签:分发,MotionEvent,dispatchTouchEvent,控件,ACTION,滑动,Android,ev,true
From: https://blog.51cto.com/u_16175630/7556828

相关文章

  • Android Framework原理解决大龄程序员的催命符
    有人说对于咱们程序员而言:每过一年,都像是在催命。35岁的坎是每个程序员都逃不过的宿命,每过一年离这个坎就又近一步。所以大家都很焦虑,而这份焦虑恰恰又被各种自媒体,公众号,博客等等平台所利用,每年都有人在说互联网又寒冬了,某某公司又大规模裁员了,Android开发不行了这类的负面的消息......
  • Android端如何实现拉取RTSP/RTMP流并回调YUV/RGB数据然后注入轻量级RTSP服务?
    技术背景我们在对接开发Android平台音视频模块的时候,遇到过这样的问题,厂商希望拉取到海康、大华等摄像机的RTSP流,然后解码后的YUV或RGB数据回给他们,他们做视频分析或处理后,再投递给轻量级RTSP服务模块或RTMP推送模块,实现处理后的数据,二次转发,本文以拉取RTSP流,解析后再注入轻量级RTS......
  • Fragment初学7——Fragment在Android开发中的应用1
    Fragment的常用功能通过getFragmentManager()方法,可以得到FragmentManager对象,主要完成下面的功能(1).得到已经存在Fragment对象如果该fragment在布局文件中指定了id,通过findFragmentById()得到对象,或者指定了tag可以通过findFragmentByTag()得到对象Fragment fragment = getFra......
  • Fragment初学8——Fragment在Android开发中的应用2
    Fragment都是依附于Activity的,通信方式大致也分为如下几种:如果Activity中包含自己管理的Fragment的引用,可以通过直接引用访问所有的Fragment的public方法 如果Activity中未保存任何Fragment的引用,那么可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得......
  • Android 妙用TextView实现左边文字,右边图片
    有时候,需要文字在左边,右边有个箭头,我个人之前会有两种做法:使用线性布局来实现或者使用约束布局,一个左对齐,一个右对齐这几天突然想到是否可以使用TextView的设置图标的方式实现,研究发现确实可以实现我的需求,也是记录下文字和图标左右显示效果:代码:<TextViewandroid:id="@+id/......
  • Android开发中Button背景颜色不能修改问题及解决方法
    在Android中,Button是一种按钮组件,用户能够在该组件上点击,并引发相应的事件处理函数。在进行Android开发的时候,都需要使用到按钮,但是对于初学者来说,刚开始的按钮都是默认的主题颜色,不管怎么修改都变不了颜色,在此记录一下踩过的坑。问题:使用AndroidStudio进行android开发时,不管是......
  • 简历被筛、面试被拒?Android求职者们如何给自己争取面试机会?
    前言相信各位小伙伴在求职过程中,都会遇到简历投递之后已读不回、面试邀请迟迟没有音讯以及初试被刷的情况。一般来说,大多数小伙伴就会直接选择放弃这家公司了,但是!先别急着换下一家投递呀!求职面试是彼此双向选择的一个过程,不要觉得有心理负担,也不要觉得不好意思,如果是真的很需要一个......
  • 最全详解Android设备UDID还是唯一ID?
    这篇文章主要介绍了Android设备UDID还是唯一ID?我觉得挺不错的,现在分享给大家,也给大家做个参考。我想为我的Android应用程序生成android设备唯一ID,以根据用户设备udid创建收藏夹.所有设备都有唯一的ID.importandroid.provider.Settings.Secure;privateStringandroid_id=Se......
  • 2022最新手机设备标识码(IMEI、MEID、UDID、UUID、ANDROID_ID、GAID、IDFA等)教程
    Android篇 1IMEI和MEID(1)IMEI(InternationalMobileEquipmentIdentity)是国际移动设备身份码的缩写,国际移动装备辨识码,只有Android手机才获取的到,是由15位数字组成的"电子串号",比如像这样359881030314356,它与每台移动电话机一一对应,而且该码是全世界唯一的。它是GSM设备返......
  • 2022Android设备唯一标识(AndroidID,OAID等 )
    一、ID体系:你只是一串代码想要了解OAID,我们首先需要明白ID体系:想要追踪一个用户就必须先找到用户,在这个过程中,标识符(ID)就像我们的另一张身份证,它们就代表了数字化之后的你和我。不同App可能通过某些唯一标识符对你进行强制跟踪,广告平台则会通过这个唯一标识符对你进行用户画......