Android学习之路--View--事件传递机制

2017-01-14 08:47:56来源:CSDN作者:liuyulongjiayi人点击

     之前我们介绍了安卓的四大组件,接下来我们说说Android的事件传递机制,我们都知道,任何的组件都是在一个laytout里进行摆放的。不管是哪种layout,都是继承自ViewGroup容器。而我们所要研究的也就是从activity—viewgroup–XXXview,一级一级的传递。


     事件的传递就好像一个任务下来,总有人要做,我们现在分配3个角色,正好对应不同的层级,大boss领导,中层主管,以及下层小兵。进行这么分配也是为方便理解记忆。


首先,我们首先说说时间分发主要用到的方法:

dispatchTouchEvent:用来判断是否进行事件分发
onInterceptTouchEvent:用来判断是否进行事件拦截
onTouchEvent:用来处理事件行为


1、首先我们有应用程序activity:

public class TestMain extends Activity {   private String tag = TestMain.class.getSimpleName();   @Override   protected void onCreate(Bundle savedInstanceState) {       super.onCreate(savedInstanceState);       setContentView(R.layout.testevent);   }   @Override   public boolean dispatchTouchEvent(MotionEvent ev) {       LogUtil.i(tag,"TestMain dispatchTouchEvent");       return super.dispatchTouchEvent(ev);   }   @Override   public boolean onTouchEvent(MotionEvent event) {       LogUtil.i(tag,"TestMain onTouchEvent");       return super.onTouchEvent(event);   }}

activity里只有这俩个方法,是因为事件要不要分发,要分发就分发,不分发就自己处理。


2、涉及到是ViewGroup容易,这里的存放的都是子view,这里涉及到一个事件的分发,和是否拦截的问题。

public class TestLinearlayout extends LinearLayout {    String tag = TestLinearlayout.class.getSimpleName();    public TestLinearlayout(Context context) {        super(context);    }    public TestLinearlayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        LogUtil.i(tag,"+++++++++TestLinearlayout dispatchTouchEvent ");        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        LogUtil.i(tag,"++++++++ TestLinearlayout onInterceptTouchEvent ");        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        LogUtil.i(tag,"++++++++ TestLinearlayout onTouchEvent ");        return super.onTouchEvent(event);    }}

这个是layout布局文件,我们引用的时候,就引用当前的layout文件。


3、接下来就是我们自定义的TextView,其实也没啥,就是几个方法。

public class TestTextView extends TextView {    String tag = TestTextView.class.getSimpleName();    public TestTextView(Context context) {        this(context,null);    }    public TestTextView(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        LogUtil.i(tag, "------TestTextView dispatchTouchEvent ");        return super.dispatchTouchEvent(event);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        LogUtil.i(tag, "------TestTextView onTouchEvent ");        return true;    }}

这是我们最里面的布局。

统一的layout为:

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center"    android:orientation="vertical">    <com.android.app.view.TestLinearlayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical"        android:background="@drawable/myshape"        android:gravity="center"        android:layout_margin="50dp">        <com.android.app.view.TestTextView            android:id="@+id/myview"            android:layout_width="200dp"            android:layout_height="200dp"            android:background="@drawable/myshape"            android:text="最小组件"            android:gravity="center"/>    </com.android.app.view.TestLinearlayout></LinearLayout>

为清晰的显示我们的组件边间,加一个背景shape:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android">    <stroke android:color="@color/colorPrimary" android:width="1px"></stroke>    <solid android:color="@color/white"></solid></shape>

页面效果看起来是这个样子的:

注:最外面的就是咱们的activity界面了,中间的边框就是我们layout,里面的框就是我们的textView了。


接下来,我们就开始点击各种事件,看下Event是怎么传递的了。
有一下几种case:

1、首先,我们点击最外面的activity,日志如下:
    1·1 都是正常的返回的都是super

I/TestMain: TestMain dispatchTouchEventI/TestLineayout: TestLinearlayout dispatchTouchEventI/TestLinearlayout: TestLinearlayout onInterceptTouchEventI/TestTextView: TestTextView dispatchTouchEventI/TestTextView: TestTextView onTouchEventI/TestLinearlayout: TestLinearlayout onTouchEventI/TestMain: TestMain onTouchEvent

   #我们看到事件都是一级一级向下传递,然后在向上传递

    1·2如果activity中的dispatchTouchEvent返回true,则打印

I/TestMain: TestMain dispatchTouchEvent

    相当于当前累消费了此事件,就是我能干这件事不用下边的人干,不在放下传递

    1.3如果activity中的dispatchTouchEvent返回false,则打印:

I/TestMain: TestMain dispatchTouchEvent

    相当于当前类消费事件不在往下传递。

2、我们在点击,layout中的参数设置:

     2.1 正常super传递,则和1.1一样,事件正常传递

     2.2 layout.dispatchTouchEvent 返回ture时,则打印:

I/TestMain: TestMain dispatchTouchEventI/TestLinearlayout: TestLinearlayout dispatchTouchEvent

    相当于当前类消费了此事件,不往下下传递。翻译过来就是领导先不干,让下边的人干, 结果主管一看,擦,自己不干,也没让下面的人干,也没返给领导到底干了没干。

    2.3 layout.dispatchTouchEvent,如果返回false,则打印:

 I/TestMain: TestMain dispatchTouchEvent I/TestLinearlayout: TestLinearlayout dispatchTouchEvent I/TestMain: TestMain onTouchEvent

    相当于当前累没有消费此事件,但是不在继续分发,直接返回让父类消费。翻译过来就是领导先不干,让下边的人干, 结果主管一看也干不了,那下面的人就更干不了了,返回给领导,领导说,擦,这帮废物,还得我自己干,执行容器ontouchevent方法

     2.4 layout.dispatchTouchEvent 返回super类,继续向下传递,但layout.onInterceptTouchEvent 返回true,则打印:

I/TestMain: TestMain dispatchTouchEventI/TestLinearlayout: TestLinearlayout dispatchTouchEventI/TestLinearlayout: TestLinearlayout onInterceptTouchEventI/TestLinearlayout: TestLinearlayout onTouchEventI/TestMain: TestMain onTouchEvent

    此类有能力消费了此事件,拦截,不往下下传递。翻译过来就是领导先不干,让下边的人干, 结果主管一看,汗,简单,能干,那就拦截,自己先处理了这件事, layout.touch事件就是主管在处理事情,如果处理成功, 返回true,就不会执行父类的ontouch方法,就是我处理了,你不用在处理了,如果返回false,相当于我处理了一顿结果还没处理成。还得让父类解决,就继续执行父类的onTouchevent方法,即TestMain onTouchEvent。(此时:TestLinearlayout onTouchEvent方法返回false和super的作用一致,都是我处理不了)

    2.5 类还原初始化,layout.dispatchTouchEvent 返回super类,继续向下传递,但layout.onInterceptTouchEvent 返回false,则打印:

I/TestMain: TestMain dispatchTouchEventI/TestLinearlayout: TestLinearlayout dispatchTouchEvent I/TestLinearlayout: TestLinearlayout onInterceptTouchEvent I/TestTextView: TestTextView dispatchTouchEvent I/TestTextView: TestTextView onTouchEvent I/TestLinearlayout:TestLinearlayout onTouchEvent I/TestMain: TestMain onTouchEvent

    此类暂时不知道能不能干,继续向下传递,让手下先干的,我不进行拦截。看下面的人办的怎么样。(因为我们都是返回的super,在这里我们可以认为手下处理不了,返回主管处理不了,返回领导,让领导处理,这就是打印的全过程)。

3、textview中的参数设置

    3.1 正常super传递,则和1.1一样,事件正常传递

    3.2 textview.dispatchTouchEvent 返回ture时,则打印

I/TestMain: TestMain dispatchTouchEventI/TestLinearlayout: TestLinearlayout dispatchTouchEvent I/TestLinearlayout: TestLinearlayout onInterceptTouchEvent I/TestTextView: TestTextView dispatchTouchEvent 

此类消费了事件,不进行传递,和2.2一样,只不过角色换成了手下,你说气不气人,你干成干不成总有个回话了吧,上头也不知道个结果

    3.3 textview.dispatchTouchEvent 返回false时,则打印:

I/TestMain: TestMain dispatchTouchEventI/TestLinearlayout: TestLinearlayout dispatchTouchEvent I/TestLinearlayout:TestLinearlayout onInterceptTouchEvent I/TestTextView:TestTextView dispatchTouchEvent I/TestLinearlayout:TestLinearlayout onTouchEvent I/TestMain: TestMain onTouchEvent

    即当前类没有消费此事件,返回给父类消费,翻译过来就是:分给我了任务,我一看结局不了,立马返给主管,让主管解决,主管解决的情况如何看2.4layout.touchevent 返回解释。

     3.4 textview.dispatchTouchEvent 返回super,ontouch事件返回true时,则打印:

I/TestMain: TestMain dispatchTouchEventI/TestLinearlayout: TestLinearlayout dispatchTouchEvent I/TestLinearlayout: TestLinearlayout onInterceptTouchEvent I/TestTextView: TestTextView dispatchTouchEvent I/TestTextView: TestTextView onTouchEvent

即当前类有能力消费此事件。不在向上级传递。翻译过来就是:领导先不干,传给主管,主管懒的看也不看,一下传给手下,手下一看,这么简单,我能处理,就处理了,返回true。就是我处理了此事,你们不用再处理了,如果返回false,就是说我处理了一顿也没处理,在返给主管吧,主管的处理情况见2.4解释翻译。


好了,Android之View事件机制说了这么多,估计大家也有点绕。自己敲的代码自己亲自测试下。增进下了解与记忆,并且结合源码,自己实践下。我也不放整个项目了,就放几个简单的文件,方便下懒人大神吧。

View的机制是安卓中的难点,这个得慢慢消化,并且这方面的知识在面试中也是经常问到的问题。还需大家要多多研究啊!


2017年第一份知识记录,好几天没写了,这几天赶紧补上。也㊗️大家2017技术上多多增进,知识慢慢积累。早日铸就高塔。

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台