Android事件分发的初识

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011557841/article/details/52099247

Android的事件分发的理论网络上已经有很多了,今天自己通过实例来深刻理解ViewGroup和View的事件分发,只有理解了其分发原理,就很容易处理平时遇到的滑动冲突的问题。

ViewGroup

首先看ViewGroup的事件分发:
自定义一个LinearLatout:

public class CustomLayout extends LinearLayout {
    private static final String TAG = "CustomLayout";
    public CustomLayout(Context context) {
        super(context);
    }

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

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

第一步:拦截事件 onInterceptTouchEvent的返回值为true,则会调用OnTouchEvent事件

public class CustomLayout extends LinearLayout {
    private static final String TAG = "CustomLayout";
    public CustomLayout(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d(TAG, "dispatchTouchEvent: ");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d(TAG, "onInterceptTouchEvent: ");
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: ");
        return super.onTouchEvent(event);
    }
}

Debug的结果:
CustomLayout: dispatchTouchEvent:
CustomLayout: onInterceptTouchEvent:
CustomLayout: onTouchEvent:

第二步:不拦截事件 onInterceptTouchEvent的返回值为false

public class CustomLayout extends LinearLayout {
    private static final String TAG = "CustomLayout";
    public CustomLayout(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d(TAG, "dispatchTouchEvent: ");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d(TAG, "onInterceptTouchEvent: ");
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: ");
        return super.onTouchEvent(event);
    }
}

Debug结果:
CustomLayout: dispatchTouchEvent:
CustomLayout: onInterceptTouchEvent:

View

view作为一个单一的对象,当事件分发给它时,他只有处理和不处理两种选择,所以没有拦截事件。
第一种:如果注册了OnTouchlistener()监听事件,首先调用的是它的OnTouchListener(),如果它的返回值为True,则事件就会被消费掉;

public class CustomView extends Button {
    private static final String TAG = "CustomView";
    public CustomView(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "dispatchTouchEvent: ");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: ");
        return true;
    }
}

View注册了OnTouchListener()事件:

 mCustomView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.d(TAG, "onTouch: ");
                return true;
            }
        });

Debug的结果:
CustomLayout: dispatchTouchEvent:
CustomLayout: onInterceptTouchEvent:
CustomView: dispatchTouchEvent:
DispatchEventActivity: onTouch:
从结果可以证明上面的结论,没有调用OnTouchEvent()。

第二种:如果没有注册OnTouchListener()监听事件,就会调用OnTouchEvent()方法,如果OnTouchEvent的返回值为True,则表示该View消费了该事件。

public class CustomView extends Button {
    private static final String TAG = "CustomView";
    public CustomView(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "dispatchTouchEvent: ");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: ");
        return true;
    }
}

Debug的结果:
CustomLayout: dispatchTouchEvent:
CustomLayout: onInterceptTouchEvent:
CustomView: dispatchTouchEvent:
CustomView: onTouchEvent:
结果可以证明直接回调用OnTouchEvent()方法。

第三种:如果注册了OnClickListener()监听事件,必须OnTouchEvent()返回值必须为父类的方法。

public class CustomView extends Button {
    private static final String TAG = "CustomView";
    public CustomView(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "dispatchTouchEvent: ");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: ");
        return super.onTouchEvent(event);
    }
}
mCustomView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "onClick: ");
            }
        });

Debug的结果:
CustomLayout: dispatchTouchEvent:
CustomLayout: onInterceptTouchEvent:
CustomView: dispatchTouchEvent:
DispatchEventActivity: onTouch:
CustomView: onTouchEvent:
DispatchEventActivity: onClick:

第四种:OnTouchEvent()消费了该事件:

public class CustomView extends Button {
    private static final String TAG = "CustomView";
    public CustomView(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG, "dispatchTouchEvent: ");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: ");
        return true;
    }
}

Debug结果:
CustomLayout: dispatchTouchEvent:
CustomLayout: onInterceptTouchEvent:
CustomView: dispatchTouchEvent:
DispatchEventActivity: onTouch:
CustomView: onTouchEvent:
结果证明没有调用OnClickListener()。
由此得出的结论可以如下:
对于一个单一的View而言,事件的优先级为OnTouchListener()–OnTouchEvent()—OnClickListener();

猜你喜欢

转载自blog.csdn.net/u011557841/article/details/52099247
今日推荐