看完你就了解了-Android事件分发机制

前言

懵懵懂懂搞了几年安卓,对于事件分发这一块,总是感觉没有完全理解清楚。看了很多技术文章,自信感觉已经差不多了,然后一到面试,感觉总是说不出来。然后换了一套方式来理解,然后发现,事件分发也就是那么回事。

举例理解

举一个例子来说明,某天你老板看到个比较难的效果觉得很炫酷,然后就和产品经理随口给派发了一个任务,产品经理把这个任务又给派发到组长。组长是个搞技术的,虽然自己有能力解决一些问题,但是发现自己有小弟,当仁不让,任务给了程序员。然后程序员发现,整个技术部就我最小,我没有小弟,然后只能苦逼的看任务。然后一看,发现自己搞不了。老老实实和组长说干不了。然后组长也就一推四五六,就和产品经理说做不了,直接报告给老板吧,这太难了。算了把,凑合凑合现在的也能用。老板听取到产品经理的建议以后放弃了任务。然后这次任务流程可以概括为下面的图。(ps:不经过任何拦截的流程)

上述图是不经过任何拦截的流程,在事实上,也会有很多种可能:

  1. 老板发布的任务太难,产品经理一看,立即劝导老板不要做这个,然后事件终止
  2. 组长是个比较会照顾人的或者说知道程序员是个新手干不了,直接给完成了任务,然后反馈给产品经理,然后事件终止
  3. 程序员干不了,又给组长,组长能力强给干完了,然后反馈给产品经理,事件终止
  4. 程序员能力比较强直接给做了,然后报告给组长、组长又给产品经理然后然后事件终止了
  5. 程序员能力特强,完成以后给组长,组长一看直接给老板,然后事件就到此终止了


上面描述了安卓的事件分发机制和处理机制,然后我们归类一下方法
activity:
(1)dispatchTouchEvent                该方法用来分发事件,一般不会重写这个方法 (给任务给组长)
(2)onTouchEvent                          用来处理事件,常见重写(当返回为true: 劝导老板)


viewGroup:
(1)dispatchTouchEvent                该方法用来分发事件,一般不会重写这个方法 (给任务给程序员)
(2)onInterceptTouchEvent           拦截事件(想不想做)
(2)onTouchEvent                         用来处理事件,常见重写(当返回为true: 自己做 | 接到程序员求助然后做)


view:
(1)dispatchTouchEvent               该方法用来分发事件,一般不会重写这个方法 (判定自己是否能做)
(2)onTouchEvent                         用来处理事件,常见重写(当返回为true: 自己做)
 

代码验证

分别编写activity、viewGroup、view进行验证:

 

新建一个项目,先来写ActivityA,代码如下:

public class ActivityA extends AppCompatActivity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
       
        if (ev.getAction() == MotionEvent.ACTION_DOWN) { //判定是否为点击
            Log.e("测试--Down----->", "ActivityA:dispatchTouchEvent");
      
        } else if (ev.getAction() == MotionEvent.ACTION_UP) { //判定是否为擡起
            Log.e("测试--UP------->", "ActivityA:dispatchTouchEvent");
        } else {
            Log.e("测试--Other---->", "ActivityA:dispatchTouchEvent");
        }
        return super.dispatchTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("测试--Down----->", "ActivityA:onTouchEvent");
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            Log.e("测试--UP------->", "ActivityA:onTouchEvent");
        } else {
            Log.e("测试--Other---->", "ActivityA:onTouchEvent");
        }
        return super.onTouchEvent(event);
    }
}


同理,编写ViewGroupB,如下

public class ViewGroupB extends LinearLayout {


    public ViewGroupB(Context context) {
        super(context);
    }

    public ViewGroupB(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ViewGroupB(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("测试--Down----->","ViewGroupB:dispatchTouchEvent");
        } else if (ev.getAction() == MotionEvent.ACTION_UP) {
            Log.e("测试--UP------->","ViewGroupB:dispatchTouchEvent");
        } else {
            Log.e("测试--Other---->","ViewGroupB:dispatchTouchEvent");
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("测试--Down----->","ViewGroupB:onInterceptTouchEvent");
        } else if (ev.getAction() == MotionEvent.ACTION_UP) {
            Log.e("测试--UP------->","ViewGroupB:onInterceptTouchEvent");
        } else {
            Log.e("测试--Other---->","ViewGroupB:onInterceptTouchEvent");
        }
        return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("测试--Down----->","ViewGroupB:onTouchEvent");
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            Log.e("测试--UP------->","ViewGroupB:onTouchEvent");
        } else {
            Log.e("测试--Other---->","ViewGroupB:onTouchEvent");
        }
        return super.onTouchEvent(event);
    }
}

再编写ViewC,代码如下

public class ViewC extends View {


    public ViewC(Context context) {
        super(context);
    }

    public ViewC(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("测试--Down----->","ViewC:dispatchTouchEvent");
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            Log.e("测试--UP------->","ViewC:dispatchTouchEvent");
        } else {
            Log.e("测试--Other---->","ViewC:dispatchTouchEvent");
        }
        return super.dispatchTouchEvent(event);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("测试--Down----->","ViewC:onTouchEvent");
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            Log.e("测试--UP------->","ViewC:onTouchEvent");
        } else {
            Log.e("测试--Other---->","ViewC:onTouchEvent");
        }
        return super.onTouchEvent(event);
    }
}

将其写入嵌套在一起,activity_test.xml。代码如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorFE6016"
        android:gravity="center"
        android:orientation="vertical">

    <com.hysf.ym.custorm.meView.fenfa.ViewGroupB
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:background="@color/color7F6F51"
            android:gravity="center">

        <com.hysf.ym.custorm.meView.fenfa.ViewC
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:background="@color/colorFD9C1A" />


    </com.hysf.ym.custorm.meView.fenfa.ViewGroupB>


</RelativeLayout>

得到的效果如下:

最外面橘色的是ActivityA,大一点的灰色的是ViewGroupB,中间偏黄色的是ViewC,现在我们点击ViewC ,得到如下流程:
 

从打印的结果,我们可以很清楚到看到事件的流程:

      首先ActivityA得到了事件,由它的dispatchTouchEvent方法来分发事件,传给了ViewGroupB,然后由于ViewGroupB的onInterceptTouchEvent方法没有做出拦截,因此事件传递给了ViewC,而ViewC的onTouchEvent没有处理,就又调用给ViewGroupB,继ViewGroupB的onTouchEvent也没有处理,然后传给ActivityA的onTouchEvent方法,然后按下操作的流程就结束了,至于up事件又调用了ActivityA的dispatchTouchEvent和onTouchEvent,我们稍后再说。

实验验证:


ActivityA

测试1:单独设置ActivityA的onTouchEvent方法返回值设置为true,测试结果如下
 


测试2:单独设置ActivityA的onTouchEvent方法返回值设置为false,测试结果如下:

 ViewGroudB:

测试1:单独设置ViewGroupB的onInterceptTouchEvent方法返回值设置为true,测试结果如下:

 在测试1的基础上,设置ViewGroupB的onTouchEvent方法返回值设置为true,测试结果如下:
 

在测试1的基础上,设置ViewGroupB的onTouchEvent方法返回值设置为false,测试结果如下: 
 

 

 

测试2:单独设置ViewGroupB的onInterceptTouchEvent方法返回值设置为false,测试结果如下:

 在测试2的基础上,设置ViewGroupB的onTouchEvent方法返回值设置为true,测试结果如下:
 

在测试2的基础上,设置ViewGroupB的onTouchEvent方法返回值设置为false,测试结果如下: 
 

ViewC

测试1:单独设置ViewC的onTouchEvent方法返回值设置为true,测试结果如下
 


测试2:单独设置ViewC的onTouchEvent方法返回值设置为false,测试结果如下:

 

 总结:
 

  • ACTION_DOWN可以理解成所有事件的一种,或者理解成探路的
  • 当ACTION_DOWN判断好具体是怎么dispatch,怎么消费的以后,对应的ACTION_MOVE和ACTION_UP就会按照消费的顺序,进行执行
  • 当然,如果中间有拦截,也是按消费的路线进行
  • 对于事件的拦截,我们主要重写就是OnInterceptTouchEvent和onTouchEvent方法。两句就可以总结:

 (1)对于事件的传递,返回结果为true,表示拦截,不再往下传递,为false,不拦截,继续往下传递。主要针对的就是                                  OnInterceptTouchEvent方法。
        (2)对于事件的处理,返回结果为true,表示拦截,不再往上传递(即我处理的很完美,不需要你再来审核我!),返回结果为                      false(没有成功处理事件),继续向上传递。(onTouchEvent方法。)
   

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章