本篇讲述的是Android控件的事件机制,这也是Android自定义控件的核心部分。由于Android系统越来越完善,现在它的事件处理机制也完善的越来越好,不过整体的核心思想是没有变化的,所以在本篇博客中是使用的较低版本的Android源代码来进行事件处理的分析的。

一、事件机制的整体概述:

Android控件的事件处理机制采用的是事件由外向内传递的方式,废话不多说上一张图便可以清晰明了,图如下所示:

Android 自定义控件xml不显示 android自定义控件步骤_Android 自定义控件xml不显示


二、事件机制的详细分析

在事件处理的过程中主要涉及如下三个方法:

2.1 dispatchTouchEvent:

这个方法用于分发事件,它可以说是事件处理的总控开关,它一旦失效那么整个控件的事件处理体系可以算是破碎了。ViewGroup中针对这个方法的源码实现如下所示:

View mTarget=null;//保存捕获Touch事件处理的View
    public boolean dispatchTouchEvent(MotionEvent ev) {

        //....其他处理,在此不管

        if(ev.getAction()==KeyEvent.ACTION_DOWN){
            //每次Down事件,都置为Null

            if (disallowIntercept || !onInterceptTouchEvent(ev)) {
            mTarget=null;
            View[] views=getChildView();
            for(int i=0;i<views.length;i++){
                if(views[i].dispatchTouchEvent(ev)){
                    mTarget=views[i];
                    return true;
                }
            }
          }
        }
        //当子View没有捕获down事件时,ViewGroup自身处理。这里处理的Touch事件包含Down、Up和Move
        if(mTarget==null){
            return super.dispatchTouchEvent(ev);
        }
        if (!disallowIntercept && onInterceptTouchEvent(ev)) {
            //其他操作,不管

            // clear the target
            mMotionTarget = null;
            return true;
        }
    //这一步在Action_Down中是不会执行到的,只有Move和UP才会执行到。
        return mTarget.dispatchTouchEvent(ev);
    }
2.2 onInterceptTouchEvent:

这个方法用于阻隔事件的传递,它可以理解成建立在高速路上的收费站。这个方法存在于ViewGroup及其子类中,它的存在本来就是为了方便控件的容器来操纵控件的。ViewGroup中针对这个方法的源码实现如下所示:

public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
}
2.3 onTouchEvent

这个方法用来处理事件,在它的方法内部可以针对具体的事件类型来处理相应的业务逻辑。
View中针对这个方法的源码实现如下所示:

public boolean onTouchEvent(MotionEvent event) {
        //其他操作,不管 如果可以点击则为true
        return false;
}

三、场景辅助理解

Android 自定义控件xml不显示 android自定义控件步骤_事件处理_02


说明:家规相当于事件传递的基本规则;梨相当于MotionEvent;传递梨的过程相当于dispatchOnTouchEvent;迫切需要吃相当于onInterceptTouchEvent;请求父亲不要跟我强相当于调用requestDisallowedInterceptTouchEvent(true);

注意:除了最后一个场景之外只要处理如何吃梨一般都会触发MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE、MotionEvent.ACTION_UP这三类事件,最后一个场景处理会触发这三个事件外还会触发MotionEvent.ACTION_CANCEL这类事件,因为中途抢走事件子View肯定要先取消事件,然后再将取消事件之前的事件状态交给抢走的控件处理;