Android takes you to read event distribution

Working for some time, it is necessary to grasp the event delivery mechanism, the recent study a little, record the experience.
Android 1 events
android touch event is more, the package MotionEvent class, click, touch, slide our common event

  • MotionEvent.ACTION_DOWN
  • MotionEvent.ACTION_MOVE
  • MotionEvent.ACTION_UP
  • MotionEvent.ACTION_CANCEL

2 core methods
before passing to understand the mechanism, we need to learn a few ways.
2.1ViewGroup

  • dispatchTouchEvent distribution event, and the event down to accept the default distribution. If it returns true, intercept events, not distribution. The same below.
  • onInterceptTouchEvent default pre-event returns false, true to interception return
  • onTouchEvent default event processing returns false, not to consume events. If you set clickable = true root layout or code, you super.onTouchEvent returns true, indicating that consumer event.

2.2View

  • dispatchTouchEvent
  • onTouchEvent handle events need to see the return value of the property clickable == true view

2.3View / ViewGroup of onTouchEvent return value:

  • If the view / viewGroup clickable, such as Button, clickable = true, then return true super.onTouchEvent
  • If you view / viewGroup not clickable, such as TextView, clickable = false, it returns false super.onTouchEvent
  • Set view / viewGroup clickable in xml attribute is true, then the view: super.onTouchEvent returns true

2.4 Core

  • clickable affect the return value super.onTouchEvent
  • If it returns false, View only handle down event, subsequent events will not trigger
  • If it returns true, View of down \ move \ up can trigger

3 event passes
  a full touch screen events: a finger press, slide, lift. This event consists of a action_down, several action_move, and a action_up components. So it is in our screen how to pass it?
By default, the event delivery process is to ViewGroup from Activity to View, and ultimately received by the View. Figure:

  

We define a MyViewGroup and a MyView, method of printing them.
MyViewGroup, clickable as false, super.onTouchEvent default is false, do not consume events

public class MyViewGroup extends FrameLayout {

    String Tag = "===MyViewGroup";

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            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(ev);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            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(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            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(ev);
    }
}

MyView inheritance TextView, clickable default false, super.onTouchEvent default is false, do not consume events

public class MyView extends android.support.v7.widget.AppCompatTextView {

    String Tag = "===MyView";

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            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(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            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(ev);
    }
}

activity layout reference

<com.zcwipe.frecyclerviewdemo.MyViewGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.zcwipe.frecyclerviewdemo.MyView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/color_theme"
        android:gravity="center"
        android:text="content" />
</com.zcwipe.frecyclerviewdemo.MyViewGroup>

Events are started by action_down,
first of all activity execution super.dispatchTouchEvent distributed viewgroup.
Then viewgroup execution super.dispatchTouchEvent, super.onInterceptTouchEvent.
The last view execution super.dispatchTouchEvent, onTouchEvent. This time view in onTouchEvent where it received the action_down event.

Case 1:
If the view is not onTouchEvent in consumer action_down event (default return false, not consumption), then the event will be handed over to the father action_down layout, which is viewgroup of onTouchEvent to deal with. If viewgroup not handle. Activity will continue to the upper layer of the layout process action_down onTouchEvent event.
This completes the transfer action_down events. Because view and viewgroup did not deal with action_down event, the system will no longer pass successor event action_move, action_up. Log output

Subsequent action_move, action_up event is no longer passed to ViewGroup and View. Directly handled by the activity.

Case 2:
We return in the event view action_down's true, the consumption of this event (you can also define a button, or set clickable = true, consumer default event) then action_down event will not be passed to viewgroup and activity, that subsequent events by who is going to deal with?
action_down是由上层传递到view中的,后续动作action_move和action_up 也是如此。由于我们在子view的down中消费了事件,那么viewgroup在传递后续事件时会在onInterception方法中判断是否需要拦截此action_move、action_up动作
如果不拦截,viewgroup中onInterception不处理,动作由view的onTouchEvent处理:

如果拦截,viewgroup的action_move返回true,拦截事件,

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.e(Tag, "onInterceptTouchEvent ACTION_DOWN");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.e(Tag, "onInterceptTouchEvent ACTION_MOVE");
            return true;
        case MotionEvent.ACTION_UP:
            Log.e(Tag, "onInterceptTouchEvent ACTION_UP");
            break;
    }
    return super.onInterceptTouchEvent(ev);
}

动作由viewgroup的onTouchEvent处理

 

我们有这么一个需求,在自定义viewgroup中接受action_move事件,实现滑动效果,如何处理?
由情况1我们知道,如果view不消费down事件,viewgroup也不消费事件,那么无法实现。
由情况2我们知道,如果view消费了down事件,viewgroup也不拦截,那么也无法实现。
实现方案两种:
* view onTouchEvent中down消费,viewgroup:onInterceptTouchEvent中move拦截
* view onTouchEvent中down不消费 ,viewgroup:onTouchEvent中down消费
有时候我们不知道view是否消费了事件,那么使用以下方案写出健壮行代码,viewgroup中
1. ontouchevent down消费事件
2. onInterceptTouchEvent中move拦截

 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag, "onInterceptTouchEvent ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                return true;
//                break;
            case MotionEvent.ACTION_UP:
                Log.e(Tag, "onInterceptTouchEvent ACTION_UP");
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(Tag, "onTouchEvent ACTION_DOWN");
                return true;
            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(ev);
    }

这样可以稳定的在viewgroup中处理action_move事件了。

Guess you like

Origin www.cnblogs.com/suiyilaile/p/11135938.html