Andriod从源码的角度详解View,ViewGroup的Touch事件的分发机制

今天这篇文章主要分析的是Android的事件分发机制,采用例子加源码的方式让大家深刻的理解Android事件分发的具体情况,虽然网上很多Android的事件分发的文章,有些还写的不错,但是我还是决定写这篇文章,用我自己的思维方式来帮助大家理解Android事件分发,Android事件分发到底有多重要呢?相信很多Android开发者都明白吧,这个我就不介绍了,我也写了很多篇文章里面涉及到Android的事件处理的问题,可能不理解Android事件分发的朋友会有点难理解吧,不过没关系,相信看了这篇文章的你会对Android事件分发有进一步的理解。我这篇文章分析的源码是Android 2.2的源码, 也许你会说,干嘛不去分析最新的源码呢?我这里要解释一下,Android 2.2的源码跟最新的源码在功能效果方面是一样的,只不过最新的源码相对于Android 2.2来说更加健壮一些, Android 2.2的事件处理的代码几乎都写在一个方法体里面,而最新的源码分了很多个方法写,如果用最新的源码调用方法会绕来绕去的,相信你看的也会晕,出于这个考虑,我就拿Android 2.2的源码来给大家分析。

我们提供的服务有:成都网站设计、做网站、微信公众号开发、网站优化、网站认证、高县ssl等。为成百上千企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的高县网站制作公司

ViewGroup的事件分发机制

我们用手指去触摸Android手机屏幕,就会产生一个触摸事件,但是这个触摸事件在底层是怎么分发的呢?这个我还真不知道,这里涉及到操作硬件(手机屏幕)方面的知识,也就是Linux内核方面的知识,我也没有了解过这方面的东西,所以我们可能就往上层来分析分析,我们知道Android中负责与用户交互,与用户操作紧密相关的四大组件之一是Activity, 所以我们有理由相信Activity中存在分发事件的方法,这个方法就是dispatchTouchEvent(),我们先看其源码吧

public boolean dispatchTouchEvent(MotionEvent ev) {
                                                                                                                          
        //如果是按下状态就调用onUserInteraction()方法,onUserInteraction()方法
        //是个空的方法, 我们直接跳过这里看下面的实现
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
                                                                                                                                  
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
                                                                                                                                  
        //getWindow().superDispatchTouchEvent(ev)返回false,这个事件就交给Activity
        //来处理, Activity的onTouchEvent()方法直接返回了false
        return onTouchEvent(ev);
    }

这个方法中我们还是比较关心getWindow()的superDispatchTouchEvent()方法,getWindow()返回当前Activity的顶层窗口Window对象,我们直接看Window API的superDispatchTouchEvent()方法

/**
     * Used by custom windows, such as Dialog, to pass the touch screen event
     * further down the view hierarchy. Application developers should
     * not need to implement or call this.
     *
     */
    public abstract boolean superDispatchTouchEvent(MotionEvent event);

这个是个抽象方法,所以我们直接找到其子类来看看superDispatchTouchEvent()方法的具体逻辑实现,Window的唯一子类是PhoneWindow,我们就看看PhoneWindow的superDispattEvent()

public boolean superDispatchTouchEvent(KeyEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }

里面直接调用DecorView类的superDispatchTouchEvent方法,或许很多人不了解DecorView这个类,DecorView是PhoneWindow的一个final的内部类并且继承FrameLayout的,也是Window界面的最顶层的View对象,这是什么意思呢?别着急,我们接着往下看

我们先新建一个项目,取名AndroidTouchEvent,然后直接用模拟器运行项目, MainActivity的布局文件为


                                                                                                             
    
                                                                                                             

利用hierarchyviewer工具来查看下MainActivity的View的层次结构,如下图

Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制

好了,就分析到这里吧,差不多分析完了,还有一种情况没有分析到,例如我将CustomLayout的代码改成下面的情形,Touch事件又是怎么分发的呢?我这里就不带大家分析了

package com.example.androidtouchevent;
                                            
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
                                            
public class CustomLayout extends RelativeLayout {
                                                
    public CustomLayout(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
    }
                                            
    public CustomLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
                                            
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }
                                            
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(ev.getAction() == MotionEvent.ACTION_MOVE){
            return true;
        }
        return super.onInterceptTouchEvent(ev);
    }
                                                
                                            
}

这篇文章的篇幅有点长,如果你想了解Touch事件的分发机制,你一定要认真看完,下面来总结一下吧

1.Activity的最顶层Window是PhoneWindow,PhoneWindow的最顶层View是DecorView

2.一个clickable或者longClickable的View会永远消费Touch事件,不管他是enabled还是disabled的

3.View的长按事件是在ACTION_DOWN中执行,要想执行长按事件该View必须是longClickable的,并且不能产生ACTION_MOVE

4.View的点击事件是在ACTION_UP中执行,想要执行点击事件的前提是消费了ACTION_DOWN和ACTION_MOVE,并且没有设置OnLongClickListener的情况下,如设置了OnLongClickListener的情况,则必须使onLongClick()返回false

5.如果View设置了onTouchListener了,并且onTouch()方法返回true,则不执行View的onTouchEvent()方法,也表示View消费了Touch事件,返回false则继续执行onTouchEvent()

6.Touch事件是从最顶层的View一直分发到手指touch的最里层的View,如果最里层View消费了ACTION_DOWN事件(设置onTouchListener,并且onTouch()返回true 或者onTouchEvent()方法返回true)才会触发ACTION_MOVE,ACTION_UP的发生,如果某个ViewGroup拦截了Touch事件,则Touch事件交给ViewGroup处理

7.Touch事件的分发过程中,如果消费了ACTION_DOWN,而在分发ACTION_MOVE的时候,某个ViewGroup拦截了Touch事件,就像上面那个自定义CustomLayout,则会将ACTION_CANCEL分发给该ViewGroup下面的Touch到的View,然后将Touch事件交给ViewGroup处理,并返回true


分享名称:Andriod从源码的角度详解View,ViewGroup的Touch事件的分发机制
URL分享:http://pwwzsj.com/article/pgsdcc.html