Android开发经验谈Android开发Android技术知识

android 事件传递机制

2017-06-14  本文已影响137人  梦语少年

一.简述

android上所有的事件操作都是基于用户对屏幕的触摸与滑动进行分解,进而对用户不同的操作进行监听;如:点击事件、双击事件、长按事件等等。

一次完整的事件传递主要包含三个阶段,分别是事件的分发(Dispatch)、拦截(Intercept)、消费(Consume)。

关键词

视图与事件的对应

视图 分发 拦截 消费
Activity dispatchTouchEvent -- onTouchEvent
ViewGroup dispatchTouchEvent onInterceptTouchEvent onTouchEvent
View dispatchTouchEvent -- onTouchEvent

二.View的事件传递

代码


public class EventActivity extends AppCompatActivity {
    private static final String TAG = EventActivity.class.getSimpleName();
    EventTextView etvEvent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event);
        etvEvent = (EventTextView) findViewById(R.id.etv_event);
        etvEvent.setOnClickListener(onClickListener);
        etvEvent.setOnTouchListener(onTouchListener);
    }

    @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;
            case MotionEvent.ACTION_CANCEL:
                Log.e(TAG, "dispatchTouchEvent ACTION_CANCEL");
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.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;
            case MotionEvent.ACTION_CANCEL:
                Log.e(TAG, "onTouchEvent ACTION_CANCEL");
                break;
        }
        return super.onTouchEvent(event);
    }

    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e(TAG, "onClickListener ONCLICK");
        }
    };
    private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    Log.e(TAG, "onTouchListener ACTION_DOWN");
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.e(TAG, "onTouchListener ACTION_MOVE");
                    break;
                case MotionEvent.ACTION_UP:
                    Log.e(TAG, "onTouchListener ACTION_UP");
                    break;
                case MotionEvent.ACTION_CANCEL:
                    Log.e(TAG, "onTouchListener ACTION_CANCEL");
                    break;
            }
            return false;
        }
    };
} 


public class EventTextView extends AppCompatTextView {
    private static final String TAG = EventTextView.class.getSimpleName();

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

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

    public EventTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.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;
            case MotionEvent.ACTION_CANCEL:
                Log.e(TAG, "dispatchTouchEvent ACTION_CANCEL");
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.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;
            case MotionEvent.ACTION_CANCEL:
                Log.e(TAG, "onTouchEvent ACTION_CANCEL");
                break;
        }
        return super.onTouchEvent(event);
    }
}
<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        xmlns:tools="http://schemas.android.com/tools" 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="study.zxh.com.androidstudydemp.event.EventActivity">       
         <study.zxh.com.androidstudydemp.event.EventTextView 
                  android:id="@+id/etv_event"
                  android:layout_width="match_parent" 
                  android:layout_height="50dp" android:gravity="center_vertical" 
                  android:text="android事件传递机制测试--view"   
                  android:textSize="16dp" /> 
</LinearLayout>

代码概述

1.事件被activity 的dispatchTouchEvent消费:
dispatchTouchEvent消费事件

结论

2.事件被View 的OnTouchListener消费:
事件被View 的OnTouchListener消费
结论
3.事件被View的dispatchTouchEvent消费:
事件被View的dispatchTouchEvent消费
结论
4.事件被View的onTouchEvent消费:
事件被View的onTouchEvent消费
结论
5.事件被Activity的onClickListener消费:
事件被Activity的onClickListener消费
结论
6.事件被Activity的onTouchEvent消费:
事件被Activity的onTouchEvent消费
结论

二.View的事件传递

代码

public class EventLinearLayout extends LinearLayout {
    private static final String TAG = "EventLinearLayout";

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

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

    public EventLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.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;
            case MotionEvent.ACTION_CANCEL:
                Log.e(TAG, "dispatchTouchEvent ACTION_CANCEL");
                break;
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.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;
            case MotionEvent.ACTION_CANCEL:
                Log.e(TAG, "onTouchEvent ACTION_CANCEL");
                break;
        }
        return super.onTouchEvent(event);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<study.zxh.com.androidstudydemp.event.EventLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="study.zxh.com.androidstudydemp.event.EventActivity">

    <study.zxh.com.androidstudydemp.event.EventTextView
        android:id="@+id/etv_event"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center_vertical"
        android:text="android事件传递机制测试--view"
        android:textSize="16dp" />
</study.zxh.com.androidstudydemp.event.EventLinearLayout>

1.事件被ViewGroup的dispatchTouchEvent 消费
事件被ViewGroup的dispatchTouchEvent 消费
结论
2.ViewGroup的dispatchTouchEvent 返回false
ViewGroup的dispatchTouchEvent 返回false
结论
3.ViewGroup的dispatchTouchEvent 返回super.dispatchTouchEvent()
ViewGroup的dispatchTouchEvent 返回super.dispatchTouchEvent()
结论
4. 事件被ViewGroup的interceptTouchEvent 拦截
事件被ViewGroup的interceptTouchEvent 消费
结论
5. ViewGroup的interceptTouchEvent 返回 false
ViewGroup的interceptTouchEvent 返回 false
结论
6. ViewGroup的interceptTouchEvent 返回 super.onInterceptTouchEvent()
ViewGroup的interceptTouchEvent 返回 super.onInterceptTouchEvent()
结论
7. 事件被ViewGroup的onTouchEvent 消费
事件被ViewGroup的onTouchEvent 消费
结论
8. ViewGroup的onTouchEvent 返回false或super.onTouchEvent()
ViewGroup的onTouchEvent 返回false
ViewGroup的onTouchEvent 返回super.onTouchEvent()
结论

结论

三. 分析返回false与super的区别

(在ViewGroup嵌套ViewGroup情况下)

代码

<?xml version="1.0" encoding="utf-8"?>
<study.zxh.com.androidstudydemp.event.EventLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="study.zxh.com.androidstudydemp.event.EventActivity">

    <study.zxh.com.androidstudydemp.event.EventLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="study.zxh.com.androidstudydemp.event.EventActivity">

        <study.zxh.com.androidstudydemp.event.EventTextView
            android:id="@+id/etv_event"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center_vertical"
            android:text="android事件传递机制测试--view"
            android:textSize="16dp" />
    </study.zxh.com.androidstudydemp.event.EventLinearLayout>
</study.zxh.com.androidstudydemp.event.EventLinearLayout>

1.dispatchTouchEvent

activty的disptchTouchEvent返回false

activty的disptchTouchEvent返回false

activty的disptchTouchEvent返回super

activty的disptchTouchEvent返回super

ViewGroup的disptchTouchEvent返回false

ViewGroup的disptchTouchEvent返回false

ViewGroup的disptchTouchEvent返回super

ViewGroup的disptchTouchEvent返回super

View的disptchTouchEvent返回false

View的disptchTouchEvent返回false

View的disptchTouchEvent返回super

View的disptchTouchEvent返回super

2.interceptTouchEvent

interceptTouchEvent返回false

interceptTouchEvent返回false

interceptTouchEvent返回super

interceptTouchEvent返回super

3.onTouchEvent

onTouchEvent返回super

onTouchEvent返回super

onTouchEvent返回false

onTouchEvent返回false

总结

    1.dispatchTouchEvent返回false,事件不会继续向下传递,但是会向上调用,调用上一级的onTouchEvent,进行处理;
    2.dispatchTouchEvent返回super,事件会向下传递,调用相应等级的dispatchTouchEvent或interceptTouchEvnt进行继续处理;
    3.interceptTouchEvent与onTouchEvent返回false或super没有区别;
    备注:dispatchTouchEvent返回false和super,没有区别,因为它们没有需要向下传递的途径

四. 事件分发机制流程

事件分发机制流程
详解
  1. 事件由activity的dispatchTouchEvent开始,事件被消费即结束;
  2. 事件没有被消费,若返回false,直接调用上一级的onTouchEvent进行消费;
  3. 若返回super,会执行同级别下的相关方法,即如下两种途径:
    1). 若是ViewGroup,先执行interceptTouchEvent方法,返回true即拦截,运行同级别onTouchEvent方法进行消费;返回false或super,事件向下传递;
    2). 若不是ViewGroup,事件向下传递,进入view层,再次进行事件分发,若被消费,事件结束,若没有被消费,事件会由View的onTouchEvent依次传回到Activity的onTouchEvent方法最终结束;
完整的事件传递流程
    dispatchTouchEvent(Activity)--> dispatchTouchEvent(ViewGroup)-->  interceptTouchEvent(ViewGroup) -->dispatchTouchEvent(View)--> onTouchEvent(View) --> onTouchEvent(ViewGroup)--> onTouchEvent(Activity)
上一篇 下一篇

猜你喜欢

热点阅读