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

     之前我们介绍了安卓的四大组件,接下来我们说说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"?>
<LinearLayout
xmlns: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 dispatchTouchEvent
I/TestLineayout: TestLinearlayout dispatchTouchEvent
I/TestLinearlayout: TestLinearlayout onInterceptTouchEvent
I/TestTextView: TestTextView dispatchTouchEvent
I/TestTextView: TestTextView onTouchEvent
I/TestLinearlayout: TestLinearlayout onTouchEvent
I/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 dispatchTouchEvent
I/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 dispatchTouchEvent
I/TestLinearlayout: TestLinearlayout dispatchTouchEvent
I/TestLinearlayout: TestLinearlayout onInterceptTouchEvent
I/TestLinearlayout: TestLinearlayout onTouchEvent
I/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 dispatchTouchEvent
I/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 dispatchTouchEvent
I/TestLinearlayout: TestLinearlayout dispatchTouchEvent 
I/TestLinearlayout: TestLinearlayout onInterceptTouchEvent 
I/TestTextView: TestTextView dispatchTouchEvent 

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

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

I/TestMain: TestMain dispatchTouchEvent
I/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 dispatchTouchEvent
I/TestLinearlayout: TestLinearlayout dispatchTouchEvent 
I/TestLinearlayout: TestLinearlayout onInterceptTouchEvent 
I/TestTextView: TestTextView dispatchTouchEvent 
I/TestTextView: TestTextView onTouchEvent

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


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

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


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值