一直對Android事件分發(fā)的問題川无,搞的云里霧里的喇喉,正所謂念念不忘务荆,必有回響妆距,今日得空,整理一個文章
demo程序很簡單蛹含,AMainActivity設(shè)置了一個簡單的layout,BViewGroupxxx繼承自 ViewGroup,CView繼承自 View.
對于事件分發(fā)毅厚,各個類都包含了幾個重要的方法。
Activity中包含了兩個重要的方法
????dispatchTouchEvent
????onTouchEvent
ViewGroup 中包含了三個重要的方法
????dispatchTouchEvent
????onInterceptTouchEvent
????onTouchEvent
View 中包含了兩個重要的方法
????dispatchTouchEvent
????onTouchEvent
對于類名以及l(fā)og出現(xiàn)的多個'x',主要是為了打印日志的長度一致浦箱,方便分析
????AMainActivity
????BViewGroupxxx
????CViewxxxxxxxx
????dispatchTouchEventxxx
????onInterceptTouchEvent
????onTouchEventxxxxxxxxx
#Layout
????<?xml version="1.0" encoding="utf-8"?>
????<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
????????xmlns:app="http://schemas.android.com/apk/res-auto"
????????android:layout_width="match_parent"
????????android:layout_height="match_parent"
????????android:orientation="vertical">
????????<com.vphealthy.viewgroupdemo.BViewGroupxxx
????????????android:layout_width="200dp"
????????????android:layout_height="200dp"
????????????android:background="@color/colorPrimary">
????????????<com.vphealthy.viewgroupdemo.CViewxxxxxxxx
????????????????android:layout_width="100dp"
????????????????android:layout_height="100dp"
????????????????android:background="@color/colorAccent" />
????????</com.vphealthy.viewgroupdemo.BViewGroupxxx>
????</LinearLayout>
#AMainActivity
????@Override
????public boolean dispatchTouchEvent(MotionEvent ev) {
????????switch (ev.getAction()) {
????????????case MotionEvent.ACTION_DOWN:
????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_DOWN");
????????????????break;
????????????case MotionEvent.ACTION_MOVE:
????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_MOVE");
????????????????break;
????????????case MotionEvent.ACTION_UP:
????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_UP");
????????????????break;
????????}
????????return super.dispatchTouchEvent(ev);
????}
@Override
????public boolean onTouchEvent(MotionEvent ev) {
????????switch (ev.getAction()) {
????????????case MotionEvent.ACTION_DOWN:
????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_DOWN");
????????????????break;
????????????case MotionEvent.ACTION_MOVE:
????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_MOVE");
????????????????break;
????????????case MotionEvent.ACTION_UP:
????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_UP");
????????????????break;
????????}
????????return super.onTouchEvent(ev);
????}
#BViewGroupxxx
????@Override
????public boolean dispatchTouchEvent(MotionEvent ev) {
????????switch (ev.getAction()) {
????????????case MotionEvent.ACTION_DOWN:
????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_DOWN");
????????????????break;
????????????case MotionEvent.ACTION_MOVE:
????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_MOVE");
????????????????break;
????????????case MotionEvent.ACTION_UP:
????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_UP");
????????????????break;
????????}
????????return super.dispatchTouchEvent(ev);
????}
????@Override
????public boolean onInterceptTouchEvent(MotionEvent ev) {
????????switch (ev.getAction()) {
????????????case MotionEvent.ACTION_DOWN:
????????????????Log.i(TAG, "onInterceptTouchEvent ACTION_DOWN");
????????????????break;
????????????case MotionEvent.ACTION_MOVE:
????????????????Log.i(TAG, "onInterceptTouchEvent ACTION_MOVE");
????????????????break;
????????????case MotionEvent.ACTION_UP:
????????????????Log.i(TAG, "onInterceptTouchEvent ACTION_UP");
????????????????break;
????????}
????????return super.onInterceptTouchEvent(ev);
????}
????@Override
????public boolean onTouchEvent(MotionEvent ev) {
????????switch (ev.getAction()) {
????????????case MotionEvent.ACTION_DOWN:
????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_DOWN");
????????????????break;
????????????case MotionEvent.ACTION_MOVE:
????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_MOVE");
????????????????break;
????????????case MotionEvent.ACTION_UP:
????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_UP");
????????????????break;
????????}
????????return super.onTouchEvent(ev);
????}
#CViewxxxxxxxx
????????@Override
????????public boolean dispatchTouchEvent(MotionEvent ev) {
????????????switch (ev.getAction()) {
????????????????case MotionEvent.ACTION_DOWN:
????????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_DOWN");
????????????????????break;
????????????????case MotionEvent.ACTION_MOVE:
????????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_MOVE");
????????????????????break;
????????????????case MotionEvent.ACTION_UP:
????????????????????Log.i(TAG, "dispatchTouchEventxxx ACTION_UP");
????????????????????break;
????????????}
????????????return super.dispatchTouchEvent(ev);
????????}
????????@Override
????????public boolean onTouchEvent(MotionEvent event) {
????????????switch (event.getAction()) {
????????????????case MotionEvent.ACTION_DOWN:
????????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_DOWN");
????????????????????break;
????????????????case MotionEvent.ACTION_MOVE:
????????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_MOVE");
????????????????????break;
????????????????case MotionEvent.ACTION_UP:
????????????????????Log.i(TAG, "onTouchEventxxxxxxxxx ACTION_UP");
????????????????????break;
????????????}
????????????return super.onTouchEvent(event);
????????}
以下所有的操作都只是一種吸耿,按下->移動->抬起
# 情況A(只針對View.onTouchEvent【super,false,true】)
##情況A.1
可以看到當(dāng)我們所有的事件回復(fù)都是super時,
????//Down事件?????
????15:42:41.720 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
????15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
????15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
????15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
????15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_DOWN
????15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onTouchEventxxxxxxxxx ACTION_DOWN
????15:42:41.721 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_DOWN
????//MOVE事件
????15:50:09.583 25376-25376/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
????15:50:08.566 25376-25376/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_MOVE
????//UP事件
????15:42:41.763 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
????15:42:41.763 25128-25128/com.vphealthy.viewgroupdemo I/AMainActivity: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 Activity->ViewGroup->View->ViewGroup->Activity,
日志傳遞流程是 AMainActivity.dispatchTouchEventxxx
日志傳遞流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志傳遞流程是 CViewxxxxxxxx.dispatchTouchEventxxx->CViewxxxxxxxx.onTouchEventxxxxxxxxx
日志傳遞流程是 BViewGroupxxx.onTouchEventxxxxxxxxx
日志傳遞流程是 AMainActivity.onTouchEventxxxxxxxxx
UP&move事件則只在MainActivity中處理酷窥,為什么不傳遞給ViewGroup->View咽安?
當(dāng)Down傳遞到View.onTouchEvent,不View被消費(fèi)時蓬推,還會回傳到ViewGroup.onTouchEvent,MainActivity.onTouchEvent妆棒,
并且后續(xù)的MOVE,UP事件也不會再傳遞給ViewGroup和View了。
##情況A.2
現(xiàn)在我們將View中的onTouchEvent方法返回false,其他均不變,與(A.1)的現(xiàn)象一致糕珊。
##情況A.3
現(xiàn)在我們將View中的onTouchEvent方法返回true,其他均不變动分。
????//Down事件????
????15:52:52.666 25944-25944/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
????15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
????15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
????15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
????15:52:52.667 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_DOWN
????//MOVE事件????
????15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
????15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
????15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_MOVE
????15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_MOVE
????15:52:52.685 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_MOVE
????//UP事件????
????15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
????15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
????15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_UP
????15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_UP
????15:52:53.226 25944-25944/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: onTouchEventxxxxxxxxx ACTION_UP
Down事件的流程是 MainActivity->ViewGroup->View
日志傳遞流程是 AMainActivity.dispatchTouchEventxxx
日志傳遞流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志傳遞流程是 CViewxxxxxxxx.dispatchTouchEventxxx->CViewxxxxxxxx.onTouchEventxxxxxxxxx
UP&move事件也同于Down事件
這里與(A.1)相比就發(fā)現(xiàn)了2個區(qū)別
1.View.onTouchEvent返回ture以后,ViewGroup.onTouchEvent以及Activity.onTouchEvent不會再調(diào)用了
2.View.onTouchEvent返回ture以后红选,down和move方法不只在Activity執(zhí)行了澜公,也會分發(fā)給ViewGroup和View
#情況A結(jié)論
當(dāng)Activity,ViewGroup返回均為super時且View的dispatchTouchEvent返回super時喇肋,
只有View的onTouchEvent返回ture;之后的move及up事件才會再傳給view.
原因待補(bǔ)充坟乾?
# 情況B(針對View.dispatchTouchEvent【true】和View.onTouchEvent【super,false,true】)
##情況B.1
現(xiàn)在我們將View中的dispatchTouchEvent也返回true,onTouchEvent方法返回true,其他均不變。
????//Down事件????????
????16:12:50.244 27405-27405/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_DOWN
????16:12:50.245 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_DOWN
????16:12:50.245 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_DOWN
????16:12:50.245 27405-27405/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_DOWN
????//MOVE事件????
????16:12:50.499 27405-27405/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_MOVE
????16:12:50.500 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_MOVE
????16:12:50.500 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_MOVE
????16:12:50.500 27405-27405/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_MOVE
????//UP事件????
????16:12:50.680 27405-27405/com.vphealthy.viewgroupdemo I/AMainActivity: dispatchTouchEventxxx ACTION_UP
????16:12:50.681 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: dispatchTouchEventxxx ACTION_UP
????16:12:50.681 27405-27405/com.vphealthy.viewgroupdemo I/BViewGroupxxx: onInterceptTouchEvent ACTION_UP
????16:12:50.681 27405-27405/com.vphealthy.viewgroupdemo I/CViewxxxxxxxx: dispatchTouchEventxxx ACTION_UP
Down事件的流程是 MainActivity->ViewGroup->View
日志傳遞流程是 AMainActivity.dispatchTouchEventxxx
日志傳遞流程是 BViewGroupxxx.dispatchTouchEventxxx->BViewGroupxxx.onInterceptTouchEvent
日志傳遞流程是 CViewxxxxxxxx.dispatchTouchEventxxx
UP&move事件也同于Down事件
這里與情況與(A.3)相比就發(fā)現(xiàn)了1個區(qū)別
1.當(dāng)事件傳遞到View.dispatchTouchEvent返回ture時蝶防,View.onTouchEvent不會再被執(zhí)行甚侣,
##情況B.2
現(xiàn)在我們將View中的dispatchTouchEvent返回true,View.onTouchEvent方法返回true,其他均不變。與(B.1)的現(xiàn)象一致间学。
##情況B.3
現(xiàn)在我們將View中的dispatchTouchEvent返回true,View.onTouchEvent方法返回super,其他均不變殷费。與(B.1)的現(xiàn)象一致。
#情況B結(jié)論
現(xiàn)在我們將View中的dispatchTouchEvent返回true時低葫,表示事件被View.dispatchTouchEvent消費(fèi)宗兼,
View.onTouchEvent無論返回什么都不會被調(diào)用。
原因可以在View.java的源碼可以找到
????public boolean dispatchTouchEvent(MotionEvent event) {
????????// If the event should be handled by accessibility focus first.
????????if (event.isTargetAccessibilityFocus()) {
????????????// We don't have focus or no virtual descendant has it, do not handle the event.
????????????if (!isAccessibilityFocusedViewOrHost()) {
????????????????return false;
????????????}
????????????// We have focus and got the event, then use normal event dispatch.
????????????event.setTargetAccessibilityFocus(false);
????????}
????????boolean result = false;
????????....
????????if (onFilterTouchEventForSecurity(event)) {
????????????if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
????????????????result = true;
????????????}
????????????//noinspection SimplifiableIfStatement
????????????ListenerInfo li = mListenerInfo;
????????????if (li != null && li.mOnTouchListener != null
????????????????????&& (mViewFlags & ENABLED_MASK) == ENABLED
????????????????????&& li.mOnTouchListener.onTouch(this, event)) {
????????????????result = true;
????????????}
????????????if (!result && onTouchEvent(event)) {??//看這里
????????????????result = true;
????????????}
????????}
????????....
????}
當(dāng)CViewxxxxxxxx的dispatchTouchEvent不調(diào)用super.dispatchTouchEvent時氮采,
View的onTouchEvent當(dāng)然不會被執(zhí)行,
View的onTouchEvent不被執(zhí)行染苛,CViewxxxxxxxx.onTouchEvent形同虛設(shè)
## 情況C(針對View.dispatchTouchEvent【false】和View.onTouchEvent【super,false,true】)
由情況B得出的結(jié)論鹊漠,當(dāng)CViewxxxxxxxx的dispatchTouchEvent返回false時,CViewxxxxxxxx.onTouchEvent也是形同虛設(shè)茶行,我們來看一下會發(fā)生什么