View的事件分发机制和滑动冲突解决总结

Touch事件处理和传递

  1. 事件分类:

    ​ ACTION_DOWN, ACTION_UP, ACTION_MOVE:按下、离开、移动

    ​ ACTION_POINTER_DOWN, ACTION_POINTER_UP:多点按下、离开

    ​ ACTION_CANCEL:当控件收到前驱事件(前驱事件:一个从DOWN一直到UP的所有事件组合称为完整的手势,中间的任意一次事件对于下一个事件而言就是它的前驱事件)之后,后面的事件如果被父控件拦截,那么当前控件就会收到一个CANCEL事件,并且把这个事件会传递给它的子View,没有子View就调用父容器的dispatchTouchEvent()。

            if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
                event.setAction(MotionEvent.ACTION_CANCEL);
                if (child == null) {
                    handled = super.dispatchTouchEvent(event);
                } else {
                    handled = child.dispatchTouchEvent(event);
                }
                event.setAction(oldAction);
                return handled;
            }
    

    ViewGroup的dispatchTransformedTouchEvent方法对ACTION_CANCEL的处理

  2. 事件处理方法:

    • 传递—-dispatchTouchEvent():

      只要事件传递到了当前View,那么dispatchTouchEcent方法就一定会被调用。返回结果表示是否消耗当前事件。

    • 拦截——onInterceptTouchEvent():

      在dispatchTouchEcent方法内部调用此方法,用来判断是否拦截某个事件。如果当前View拦截了某个事件,那 么在这同一个事件序列中,此方法不会再次被调用。返回结果表示是否拦截当前事件。

    • 消费—-onTouchEvent()函数和OnTouchListener():

      在dispatchTouchEcent方法内调用此方法,用来处理事件。返回结果表示是否处理当前事件,如果不处理,那么在同一个事件序列里面,当前View无法再收到后续的事件。

  3. Android事件传递结论:

    1. 事件都是从Activity.dispatchTouchEvent()开始传递
    2. 事件由父View传递给子View,ViewGroup可以通过onInterceptTouchEvent()方法对事件拦截,停止其向子view传递
    3. 某个View一旦决定拦截事件,那么这个事件序列之后的事件都会由它来处理,并且不会再调用onInterceptTouchEvent。
    4. 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来,也就是说ACTION_DOWN必须返回true,之后的事件才会传递进来
    5. 如果一个View处理了down事件,却没有处理其他事件,那么这些事件不会交给父元素处理,并且这个View还能继续受到后续的事件。而这些未处理的事件,最终会交给Activity来处理。
    6. ViewGroup的onInterceptToucheEvent默认返回false,也就是默认不拦截事件。
    7. View没有InterceptTouchEvent方法,如果有事件传过来,就会直接调用onTouchEvent方法。
    8. View的enable属性不会影响onTouchEvent的默认返回值。就算一个View是不可见的,只要他是可点击的(clickable或者longClickable有一个为true),它的onTouchEvent默认返回值也是true。
    9. 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。
    10. OnTouchListener优先于onTouchEvent()对事件进行消费
  4. View拦截处理事件的流程,伪代码表示:

public boolean dispatchTouchEvent(MotionEvent ev){     
    boolean consum = false;     
    if(onInterceptTouchEvent(ev)){      //判断是否拦截        
        consum = onTouchEvent(ev);      //处理事件 
    }else{                              //不拦截,则交给子View的dispatchTouchEvent()方法处理,
        consum = child.dispatchTouchEvent(ev);     
    }          
    return consum; 
}

滑动冲突解决

外部拦截法:

  • 事件都经过父容器的拦截处理,如果父容器需要则拦截,如果不需要则不拦截。

  • 改写父容器的onInterceptTouchEvent(MotionEvent event)方法,确定是否拦截事件:

    • ACTION_DOWN事件返回false,使事件可以传递给子View。

    • ACTION_MOVE事件判断拦截时返回true,不拦截返回false。

    • ACTION_UP事件返回false,否则当子View处理时,无法处理click事件。

  • Example:

public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int)event.getX();
    int y = (int)event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            intercepted = false;
           break;
       }
       case MotionEvent.ACTION_MOVE: {
           if (满足父容器的拦截要求) {
                intercepted = true;
           } else {
                intercepted = false;
           }
           break;
       }
       case MotionEvent.ACTION_UP: {
           intercepted = false;
           break;
       }
       default:
           break;
       }
       return intercepted;
}

内部处理法:

  • 父容器不拦截任何事件,将所有事件传递给子元素,如果子元素需要则消耗掉,如果不需要则通过requestDisallowInterceptTouchEvent方法交给父容器处理。

  • 重写父容器的onInterceptTouchEvent方法

  • 重写子View的dispatchTouchEvent(MotionEvent event)方法

  • Example:

//重写父容器的onInterceptTouchEvent
public boolean onInterceptTouchEvent(MotionEvent event) {

     int action = event.getAction();
     if (action == MotionEvent.ACTION_DOWN) {//不处理DOWN事件,全部交给子View判断
         return false;
     } else {
         return true;
     }
 }
//重写子View的dispatchTouchEvent方法
public boolean dispatchTouchEvent(MotionEvent event) {
     int x = (int) event.getX();
     int y = (int) event.getY();

     switch (event.getAction()) {
     case MotionEvent.ACTION_DOWN: {
        //父Viewgroup不处理onInterceptTouchEvent回调
         parent.requestDisallowInterceptTouchEvent(true);
         break;
     }
     case MotionEvent.ACTION_MOVE: {
         int deltaX = x - mLastX;
         int deltaY = y - mLastY;
         if (父容器需要此类点击事件) {
            //需要父Viewgroup处理onInterceptTouchEvent回调,拦截事件
             parent.requestDisallowInterceptTouchEvent(false);
         }
         break;
     }
     case MotionEvent.ACTION_UP: {
         break;
     }
     default:
         break;
     }

     mLastX = x;
     mLastY = y;
     return super.dispatchTouchEvent(event);
 }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • 经常会有消费者疑惑,买到一瓶葡萄酒,不知道到底要不要醒酒,也没有一个参考标准,估计这样的消费者数量还不少。到底哪些...
    红酒百科全书阅读 5,844评论 0 23
  • 这里是乌尔禾魔鬼城,地处准噶尔盆地西北缘,是欧亚大陆的中心地带。 如果能够回到一亿多年前的白垩纪时代,我们所看到的...
    飞鸟的逍遥游阅读 482评论 1 6
  • 话说曹操大败袁绍,攻入冀州,曹丕随父出征。 袁绍已破,一般来说,对于敌人的家属,无非就两种结果,厚待或者赶尽杀绝。...
    周波波阅读 963评论 2 1
  • 月色泛起心潮 秋的味道 是心深处缱绻着的一丝妖娆 晚风带着丝丝凉意 触摸着夏花隐去的美丽 袅袅清茶的气息 托起夜空...
    爱度花艺阅读 673评论 29 32
  • 目录 第一章:我们所不能承受的生命之轻 第二章:刻下来的年少时光,致18岁的美好年华 第三章:我们在这个世界上所追...
    梁文成阅读 295评论 0 0