Android事件分发、拦截与处理的理解

原创 2016年06月21日 14:48:47

转载请注明出处
http://blog.csdn.net/guodongAndroid/article/details/51727272
本文来自【孫小逗的博客】

一、概述

昨天,某位黑同学问了个很奇葩的问题:禁止ViewPager的左右滑动。好吧,被问到的一瞬间就想是不是他傻X。ViewPager不滑动,干嘛还要用ViewPager,唉,无语。无语归无语,事情还是要干的。随手给他写了个自定义的ViewPager。。。。(吹牛一点都不好)

二、事件分发、拦截与处理

首先需要知道事件分发、拦截与处理分别对应着

  1. dispatchTouchEvent(MotionEvent ev)
  2. onInterceptTouchEvent(MotionEvent ev)
  3. onTouchEvent(MotionEvent event)

ViewGroup比View多了onInterceptTouchEvent(MotionEvent ev)方法,即事件拦截方法。因为ViewGroup可以包含子View,所以与子View的事件有冲突时可以进行拦截。

这三个方法默认返回值都为false。

下面看个例子会更容易理解:
自定义了两个LinearLayout和一个View,代码如下:

FirstViewGroup.java

public class FirstViewGroup extends LinearLayout
{

    private final static String TAG = "FirstViewGroup";

    public FirstViewGroup(Context context)
    {
        this(context, null);
    }

    public FirstViewGroup(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public FirstViewGroup(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        setBackgroundColor(0x88FF0000);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
        Log.d(TAG, "dispatchTouchEvent:" + ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        Log.d(TAG, "onInterceptTouchEvent:" + ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        Log.d(TAG, "onTouchEvent:" + event.getAction());
        return super.onTouchEvent(event);
    }
}

SecondViewGroup.java

public class SecondViewGroup extends LinearLayout
{

    private final static String TAG = "SecondViewGroup";

    public SecondViewGroup(Context context)
    {
        this(context, null);
    }

    public SecondViewGroup(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public SecondViewGroup(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        setBackgroundColor(0x88FFFF00);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
        Log.d(TAG, "dispatchTouchEvent:" + ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        Log.d(TAG, "onInterceptTouchEvent:" + ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        Log.d(TAG, "onTouchEvent:" + event.getAction());
        return super.onTouchEvent(event);
    }
}

MyView.java

public class MyView extends View
{
    private final static String TAG = "MyView";

    public MyView(Context context)
    {
        this(context, null);
    }

    public MyView(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        setBackgroundColor(0x6600FF00);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event)
    {
        Log.d(TAG, "dispatchTouchEvent: " + event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        Log.d(TAG, "onTouchEvent: " + event.getAction());
        return super.onTouchEvent(event);
    }
}

可以看到两个ViewGroup实现了事件分发、拦截与处理三个方法,并打印了Log,MyView实现了事件分发与处理两个方法,也打印了Log。

下面看看布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <com.sun.androidqyz.FirstViewGroup
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="40dp">

        <com.sun.androidqyz.SecondViewGroup
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="60dp">

            <com.sun.androidqyz.MyView
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </com.sun.androidqyz.SecondViewGroup>

    </com.sun.androidqyz.FirstViewGroup>

</RelativeLayout>

效果如图所示:
这里写图片描述

可以看到最外层的ViewGroup的背景色是浅红色,第二层的ViewGroup的背景色是橙色,最里面的View背景色是绿色。

现在我们点击最外层的ViewGroup,看下打印的Log如下:
这里写图片描述

可以发现事件处理的顺序是先调用事件分发(dispatchTouchEvent)——>事件拦截(onInterceptTouchEvent)——>事件处理(onTouchEvent)

接下来我们点击第二层ViewGroup,看下打印的Log如下:
这里写图片描述

可以发现现在事件处理的顺序是先调用FirstViewGroup事件分发(dispatchTouchEvent)——>FirstViewGroup事件拦截(onInterceptTouchEvent)——>SecondViewGroup事件分发(dispatchTouchEvent)——>SecondViewGroup事件拦截(onInterceptTouchEvent)——>SecondViewGroup事件处理(onTouchEvent)——>FirstViewGroup事件处理(onTouchEvent)

相信看到这,当我们点击MyView的时候,打印的Log您已经知道是什么了,让我们看看吧:
这里写图片描述

是不是和你想的一样呢?事件的分发、拦截与处理就像现实生活中领导A分发个任务给领导B,领导再把任务分发给你(MyView),你处理(onTouchEvent)完时需要向上汇报给领导B,领导B处理(onTouchEvent)完,再汇报给领导A。

在自定义控件时,很少去复写dispatchTouchEvent方法,所以这里我们只看事件拦截(onInterceptTouchEvent)。

如果领导A觉得这个任务自己就可以完成,就不去派给领导B,我们就把FirstViewGroup的onInterceptTouchEvent方法返回true,当我们点击SecondViewGroup或MyView时,我们看下Log:
这里写图片描述

说明此时领导A已经把任务拦截下,自己处理了,如果领导B拦截了任务会是怎样的呢?点击MyView时的Log如下:
这里写图片描述

如果你(MyView)受不了领导的压迫,要反抗,处理完任务后返回了true,点击MyView的Log如下:
这里写图片描述

看来是真要反抗了,处理完任务都不向领导汇报了。

三、总结

Android事件分发、拦截与处理是个复杂的过程,在开发的过程中运用的场景也很多,是Android开发必须掌握的技能。现在回过头来,不从源码的角度看看Android的事件分发、拦截与处理和现实生活中的领导分派任务又有什么区别呢?

版权声明:本文为博主原创文章,未经博主允许不得转载。

android事件拦截处理机制详解

android 事件拦截处理机制详解
  • chunqiuwei
  • chunqiuwei
  • 2014年11月13日 19:43
  • 39224

android事件分发,拦截,处理

android事件分发,事件拦截,事件处理流程
  • u013356254
  • u013356254
  • 2016年03月30日 18:43
  • 3596

Android事件分发,事件拦截,事件处理总结

对于安卓的事件分发,拦截及事件处理无论是面试还是在日常应用中都涉及的比较多,网上的帖子也很多,感觉都没说透,或者没直接点出来,我认为郭神这篇博客写的事件分发理解的挺好 http://blog.csdn...
  • shenshibaoma
  • shenshibaoma
  • 2016年10月11日 10:46
  • 1341

Android图解浅析事件拦截机制

当Android系统捕获到用户的各种输入事件后,如何准确的传递给真正的需要这个事件的控件?Android提供了一整套完善的事件传递、处理机制,来帮助开发者完成准确的事件分配与处理,这里我就不分析源码了...
  • android_cmos
  • android_cmos
  • 2016年09月01日 22:26
  • 1436

Android从零开搞系列:自定义View(9)事件分发+事件拦截(滑动冲突)

事件分发以及事件拦截的解析。
  • wjzj000
  • wjzj000
  • 2017年02月15日 22:46
  • 521

Android事件拦截机制分析

转载请注明出处: http://blog.csdn.net/qq347198688/article/details/52680091 本文出自【何嘉龙的博客】 1.引言当Android系统...
  • qq347198688
  • qq347198688
  • 2016年09月27日 13:46
  • 631

Android事件分发、拦截、响应Demo

  • 2015年07月11日 09:15
  • 5.29MB
  • 下载

Android ViewGroup拦截触摸事件详解

前言 在自定义ViewGroup中,有时候需要实现触摸事件拦截,比如ListView下拉刷新就是典型的触摸事件拦截的例子。触摸事件拦截就是在触摸事件被parent view拦截,而不会分发给其c...
  • x1617044578
  • x1617044578
  • 2014年10月14日 10:23
  • 4098

Android Touch事件分发—拦截—处理

Android Touch事件分发(dispatchTouchEvent)—拦截(onInterceptTouchEvent)—处理(onTouchEvent)转自:http://www.cnblog...
  • SetO2
  • SetO2
  • 2016年02月26日 16:46
  • 1493

Android ViewGroup拦截触摸事件详解

在自定义ViewGroup中,有时候需要实现触摸事件拦截,比如ListView下拉刷新就是典型的触摸事件拦截的例子。触摸事件拦截就是在触摸事件被parent view拦截,而不会分发给其child,即...
  • bboyfeiyu
  • bboyfeiyu
  • 2014年10月01日 21:29
  • 13805
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android事件分发、拦截与处理的理解
举报原因:
原因补充:

(最多只允许输入30个字)