大飞

大飞 关注TA

挑战一切!

大飞

大飞

关注TA

挑战一切!

  •  世界的顶端
  • 混口饭吃
  • 写了333,609字

该文章投稿至Nemo社区   Android  板块 复制链接


android事件分发分析---再探

发布于 2017/06/06 22:38 1,741浏览 0回复 7,804

                                                                                                                              Android事件分发

  一.view的事件分发

      自定义一个button,分别实现的dispatchTouchEvent()和onTouchEvent()的监听,并且在activity实现button 的onTouch()的监听

  


import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

/**
 * Created by FWMS on 2017/6/5.
 */

public class MyButton extends android.support.v7.widget.AppCompatButton {
    private String TAG=this.getClass().getName();
    public MyButton(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action=event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN://按下
                Log.e(TAG,"dispatchTouchEvent----ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE://
                Log.e(TAG,"dispatchTouchEvent----ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP://
                Log.e(TAG,"dispatchTouchEvent----ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action=event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN://按下
                Log.e(TAG,"onTouchEvent----ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE://
                Log.e(TAG,"onTouchEvent----ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP://
                Log.e(TAG,"onTouchEvent----ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }

}

在activity的监听

findViewById(mBt).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();

                switch (action)
                {
                    case MotionEvent.ACTION_DOWN:
                        Log.e(TAG, "onTouch ACTION_DOWN");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.e(TAG, "onTouch ACTION_MOVE");
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.e(TAG, "onTouch ACTION_UP");
                        break;
                    default:
                        break;
                }
                return false;
            }
        });

 布局写好了,接下来让我们来看看这三个方法dispatchTouchEvent()、onTouchEvent()、onTouch()的执行步骤

onTouch() return false的时候


执行顺序是dispatchTouchEvent()》onTouch()》onTouchEvent()

当onTouch() return true的时候


执行顺序是dispatchTouchEvent()》onTouch()     而onTouchEvent()不再执行 意味着onTouch()的时候已经将事件消费掉 不再由onTouchEvent()处理

最终得出结论:是执行顺序dispatchTouchEvent()》onTouch()》onTouchEvent()  但onTouchEvent()  不一定会执行

这还没有完 再添加一个OnClickListener事件 


最后在ACTION_UP的时候回执行 如果onTouch()已经消费了该事件OnClickListener就不会执行

二.viewgroup事件分析

viewgroup比view多了拦截事件onInterceptTouchEvent()和requestDisallowInterceptTouchEvent()

同理来实现一个自定义linelayout

package com.example.fwms.eventouchdemo;

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;

/**
 * Created by FWMS on 2017/6/5.
 */

public class MyLinelayout extends LinearLayout {
    private String TAG=this.getClass().getName();
    public MyLinelayout(Context context) {
        super(context);
    }

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

    public MyLinelayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action=event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN://按下
                Log.e(TAG,"dispatchTouchEvent----ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE://
                Log.e(TAG,"dispatchTouchEvent----ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP://
                Log.e(TAG,"dispatchTouchEvent----ACTION_UP");
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action=event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN://按下
                Log.e(TAG,"onTouchEvent----ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE://
                Log.e(TAG,"onTouchEvent----ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP://
                Log.e(TAG,"onTouchEvent----ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        int action=event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN://按下
                Log.e(TAG,"onInterceptTouchEvent----ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE://
                Log.e(TAG,"onInterceptTouchEvent----ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP://
                Log.e(TAG,"onInterceptTouchEvent----ACTION_UP");
                break;
        }
        return super.onInterceptTouchEvent(event);
    }

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        Log.e(TAG,"requestDisallowInterceptTouchEvent");
        super.requestDisallowInterceptTouchEvent(disallowIntercept);
    }
}

xml布局里面

 <com.example.fwms.eventouchdemo.MyLinelayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <com.example.fwms.eventouchdemo.MyButton
            android:id="@+id/mBt2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="ViewGroub事件" />
    com.example.fwms.eventouchdemo.MyLinelayout>

现在谁都不去消费事件,看看结果


MyLinelayout: dispatchTouchEvent》MyLinelayout: onInterceptTouchEvent》MyButton: dispatchTouchEvent》MyButton:  onTouchEvent

最终发现viewgroup会将事件一个劲的传给子view 就像妈妈又好的东西吃,自己不舍得吃,就给了孩子,然后孩子也不要,为何viewgroup也不执行onTouchEvent?????有点不太合理,分着分着就凭空消失了

而点击外部就执行了onTouchEvent,可以这么理解touch事件被view消费了,子view要向下分发意味着这个touch事件被消费了才能下发,如何证明?

onInterceptTouchEvent()返回TRUE 也就是说我不下发了,拦截掉,执行结果如下:


onInterceptTouchEvent()返回TRUE,就没有子view什么事了

最终得出结论:viewgroup会一直向子view传递事件,如果viewgroup拦截了该事件,子view就不会收到任何事件,如果viewgroup不拦截,而子view也消费了该事件,viewgroup就不会再收到。

三.事件冲突的解决

在开发中我们经常会遇到这么一个场景,viewgroup竖向滚动,子view横向滚动,这就容易发生了事件冲突,解决方法

1.viewgroup需要事件的时候onInterceptTouchEvent()返回TRUE 自己消费

2.子view不需要事件的时候requestDisallowInterceptTouchEvent(true) 请求viewgroup拦截事件,告诉viewgroup我不需要这个事件

GitHub地址

本文标签
 {{tag}}
点了个评