Android事件分发的初识

来源:互联网 发布:分手炮内射 知乎 编辑:程序博客网 时间:2024/05/20 19:46

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();

0 0
原创粉丝点击