Android 事件传递机制

当多个view重叠的时候事件是怎么处理的,又是怎么传递的,以前是一头雾水,今天通过列子进行了分析。

准备

首先准备如图的布局。其中GROUPAGROUPBVIEWC的父类,GROUPBVIEWC的父类

Android 事件传递机制_第1张图片

模拟角色:

经理->最外层ViewGroupA
组长->中间层ViewGroupB
你->最底层的码农ViewC

模拟:
经理分派任务,下属处理这个任务的过程。
先来看看代码

ViewGroup级别比较高,比View多一个onInterceptTouchEvent(拦截)。

ViewGroupA

public class ViewGroupA extends RelativeLayout{

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

        public ViewGroupA(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public ViewGroupA(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.i("joker","GroupA-DispatchTouchEvent");
            return super.dispatchTouchEvent(ev);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.i("joker","GroupA-onTouchEvent");
            return super.onTouchEvent(event);
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.i("joker","GroupA-onInterceptTouchEvent");
            return true;
        }
}

ViewGroupB

    public class ViewGroupB extends RelativeLayout {
        public ViewGroupB(Context context) {
            super(context);
        }

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

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

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.i("joker", "GroupB-DispatchTouchEvent");
            return super.dispatchTouchEvent(ev);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.i("joker", "GroupB-onTouchEvent");
            return super.onTouchEvent(event);
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.i("joker", "GroupB-onInterceptTouchEvent");
            return super.onInterceptTouchEvent(ev);
        }

    }

ViewC

public class ViewC extends View {

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

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

        public ViewC(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.i("joker", "ViewC-DispatchTouchEvent");
            return super.dispatchTouchEvent(ev);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.i("joker", "ViewC-onTouchEvent");
            return super.onTouchEvent(event);
        }

}

分析

情景1:

不做任何修改直接点击ViewCLog信息如下

I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: ViewC-DispatchTouchEvent
I/joker: ViewC-onTouchEvent
I/joker: GroupB-onTouchEvent
I/joker: GroupA-onTouchEvent

Log信息看出,正常情况,事件传递顺序:
经理 –> 组长 –> 你,先执行dispatchTouchEvent(分发),再执行onInterceptTouchEvent(拦截)

事件处理顺序:
你 –> 组长 –> 经理,事件处理都是执行onTouchEvent(处理)。

事件传递返回值:true,拦截,交给自己的onTouchEvent处理;false,不拦截,传给下属。

事件处理返回值:true,自己搞定,不用上报上司;false,上报上司处理。

初始返回都是false。

事件传递,dispatchTouchEvent一般不太会改写,只关心onInterceptTouchEvent。

情景2:

经理觉得太简单自己处理
ViewGroupAonInterceptTouchEvent返回true,我们看下Log信息:

I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupA-onTouchEvent

经理把事情做完不会在交给下面的人处理。

情景3:

经理交给组长,组长觉得太简单自己处理

ViewGroupBonInterceptTouchEvent返回true,我们看下Log信息:

I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: GroupB-onTouchEvent
I/joker: GroupA-onTouchEvent

组长把事情做完不会再交给下面的人处理。

情景4

组长觉得你做的太烂了,不敢给经理上报
ViewGroupBonTouchEvent返回true,我们看下Log信息:

I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: ViewC-DispatchTouchEvent
I/joker: ViewC-onTouchEvent
I/joker: GroupB-onTouchEvent

事件处理经过你和组长,到组长那里就结束了。

情景5:

你迫于压力,辞职不干了,任务闲置
ViewConTouchEvent返回true,我们看下Log信息:

I/joker: GroupA-DispatchTouchEvent
I/joker: GroupA-onInterceptTouchEvent
I/joker: GroupB-DispatchTouchEvent
I/joker: GroupB-onInterceptTouchEvent
I/joker: ViewC-DispatchTouchEvent
I/joker: ViewC-onTouchEvent

由于你辞职了,任务就被闲置到你这里就结束了而不会上报给上级了。

到此已经分析完整个过程不会在那样一头雾水。

再分析

给三个view添加ontouch事件

public class MainActivity extends AppCompatActivity {

        private ViewGroupA a;
        private ViewGroupB b;
        private ViewC c;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            a = (ViewGroupA) findViewById(R.id.groupa);
            b = (ViewGroupB) findViewById(R.id.groupb);
            c = (ViewC) findViewById(R.id.viewc);
            a.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    Log.i("joker", "A被点击了");
                    return false;
                }
            });
            b.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    Log.i("joker", "B被点击了");
                    return false;
                }
            });
            c.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    Log.i("joker", "C被点击了");
                    return false;
                }
            });
        }

}

在不修改的情况下默认会打印什么?
让我们看Log:

I/joker: C被点击了
I/joker: B被点击了
I/joker: A被点击了

由此证实了onTouch是从下到上。
我们只想让C的信息打印又怎么修改呢?
相信大家已经有了很清晰的思路了只需要ViewC的onTouch事件返回true;
那让C的信息不显示呢?
那就需要B进行拦截。只需要把ViewGroupB的onInterceptTouchEvent事件返回true;
到此已经明白了事件分发传递的机制。

感谢《Android群英传》和小小龙博客

你可能感兴趣的:(Android 事件传递机制)