Android 事件传递机制实测
一,这个一直不懂,着实不是办法。看了几篇文章。顺便实操下、
初识Android触摸事件传递机制
事件传递三个阶段
分发(Dispatch):事件的分发对应着dispatchTouchEvent方法,在Andorid系统中,所有的触摸事件都是通过这个方法来分发的。
boolean dispatchTouchEvent (MotionEvent ev)
这个方法中,可以决定直接消费这个事件或者将事件继续分发给子视图处理。
拦截(Intercept):事件拦截对应着onInterceptTouchEvent方法,这个方法只有在ViewGroup及其子类中才存在,在View和Activity中是不存在的。
boolean onInterceptTouchEvent (MotionEvent ev)
这个方法用来判断是否拦截某个事件,如果拦截了某个事件,那么在同一序列事件当中,那么这个方法不会被再次调用。
消费(Consume):事件消费对应着onTouchEvent方法。
boolean onTouchEvent (MotionEvent event)
用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一事件序列中,当前View无法再接收到事件
在Android系统中,拥有事件传递处理能力的有三种:
Activity:拥有dispatchTouchEvent、onTouchEvent两个方法。
ViewGroup:拥有dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三个方法。
View:拥有dispatchTouchEvent、onTouchEvent两个方法。
View事件传递机制
这里说的View指的是除了ViewGroup之外的View控件,比如TextView、Button、CheckBox等,View控件本身就是最小的单位,不能作为其他View的容器,View拥有dispatchTouchEvent、onTouchEvent两个方法,所以这里就定义了一个继承TextView的类MyTextView,通过代码查看日志,看流程如何走。
单纯的没有组合控件 或则自定义控件代码情况如下:
package com.cwj.twoday;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btn;
MyTextView tv;
MyRelativeLayout mylayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btn);
tv = findViewById(R.id.my_tv);
mylayout = findViewById(R.id.mylayout);
btn.setOnClickListener(this);
tv.setOnClickListener(this);
mylayout.setOnClickListener(this);
}
//事件分发
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("dispatchTouchEvent-分发", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("dispatchTouchEvent-分发", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("dispatchTouchEvent-分发", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("dispatchTouchEvent-分发", "取消");
break;
}
return super.dispatchTouchEvent(ev);
}
//触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("onTouchEvent", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("onTouchEvent", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("onTouchEvent", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("onTouchEvent", "取消");
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("onKeyDown", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("onKeyDown", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("onKeyDown", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("onKeyDown", "取消");
break;
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn:
break;
case R.id.my_tv:
break;
case R.id.mylayout:
break;
}
}
}
单纯点击屏幕,这里没有点击Button。
2019-03-14 17:46:24.163 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 按下
2019-03-14 17:46:24.164 6394-6394/com.cwj.twoday E/onTouchEvent: 按下
2019-03-14 17:46:24.227 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 松开
2019-03-14 17:46:24.227 6394-6394/com.cwj.twoday E/onTouchEvent: 松开
触摸就会触发触摸事件
2019-03-14 17:46:44.757 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 按下
2019-03-14 17:46:44.758 6394-6394/com.cwj.twoday E/onTouchEvent: 按下
2019-03-14 17:46:44.852 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 触摸
2019-03-14 17:46:44.853 6394-6394/com.cwj.twoday E/onTouchEvent: 触摸
2019-03-14 17:46:44.873 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 触摸
2019-03-14 17:46:44.873 6394-6394/com.cwj.twoday E/onTouchEvent: 触摸
2019-03-14 17:46:44.880 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 触摸
2019-03-14 17:46:44.880 6394-6394/com.cwj.twoday E/onTouchEvent: 触摸
2019-03-14 17:46:44.880 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 松开
2019-03-14 17:46:44.881 6394-6394/com.cwj.twoday E/onTouchEvent: 松开
执行顺序:dispatchTouchEvent→onTouchEvent
第二个:View的触发事件 测试通过View来触发触摸事件。如下
package com.cwj.twoday;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
/**
* Created by CWJ on 2019/3/14.
* Author:Chen
* Email:[email protected]
* Ver:1
* DEC:View事件传递机制
*/
@SuppressLint("AppCompatCustomView")
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@SuppressLint("LongLogTag")
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("View-dispatchTouchEvent分发", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("View-dispatchTouchEvent分发", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("View-dispatchTouchEvent分发", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("View-dispatchTouchEvent分发", "取消");
break;
}
return super.dispatchTouchEvent(ev);
}
//触摸事件
@SuppressLint("LongLogTag")
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("View-onTouchEvent触摸", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("View-onTouchEvent触摸", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("View-onTouchEvent触摸", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("View-onTouchEvent触摸", "取消");
break;
}
return super.onTouchEvent(event);
}
}
结果如下:
2019-03-14 17:48:19.869 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 按下
2019-03-14 17:48:19.870 6394-6394/com.cwj.twoday E/View-dispatchTouchEvent分发: 按下
2019-03-14 17:48:19.871 6394-6394/com.cwj.twoday E/View-onTouchEvent触摸: 按下
2019-03-14 17:48:19.985 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 触摸
2019-03-14 17:48:19.986 6394-6394/com.cwj.twoday E/View-dispatchTouchEvent分发: 触摸
2019-03-14 17:48:19.986 6394-6394/com.cwj.twoday E/View-onTouchEvent触摸: 触摸
2019-03-14 17:48:19.986 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 松开
2019-03-14 17:48:19.987 6394-6394/com.cwj.twoday E/View-dispatchTouchEvent分发: 松开
2019-03-14 17:48:19.987 6394-6394/com.cwj.twoday E/View-onTouchEvent触摸: 松开
执行顺序 :父布局.dispatchTouchEvent→View.dispatchTouchEvent→View.onTouchEvent
最后ViewGroup 的触发事件
package com.cwj.twoday;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
/**
* Created by CWJ on 2019/3/14.
* Author:Chen
* Email:[email protected]
* Ver:1
* DEC:ViewGroup事件传递机制
*/
@SuppressLint("LongLogTag")
public class MyRelativeLayout extends RelativeLayout {
public MyRelativeLayout(Context context) {
super(context);
}
public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("ViewGroup-dispatchTouchEvent分发", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("ViewGroup-dispatchTouchEvent分发", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("ViewGroup-dispatchTouchEvent分发", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("ViewGroup-dispatchTouchEvent分发", "取消");
break;
}
return super.dispatchTouchEvent(ev);
}
//触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("ViewGroup-onTouchEvent触摸", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("ViewGroup-onTouchEvent触摸", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("ViewGroup-onTouchEvent触摸", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("ViewGroup-onTouchEvent触摸", "取消");
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Log.e("ViewGroup-onInterceptTouchEvent", "按下");
break;
case MotionEvent.ACTION_MOVE://触摸
Log.e("ViewGroup-onInterceptTouchEvent", "触摸");
break;
case MotionEvent.ACTION_UP://松开
Log.e("ViewGroup-onInterceptTouchEvent", "松开");
break;
case MotionEvent.ACTION_CANCEL://取消
Log.e("ViewGroup-onInterceptTouchEvent", "取消");
break;
}
return super.onInterceptTouchEvent(ev);
}
}
结果如下:
2019-03-14 17:48:52.303 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 按下
2019-03-14 17:48:52.303 6394-6394/com.cwj.twoday E/ViewGroup-dispatchTouchEvent分发: 按下
2019-03-14 17:48:52.304 6394-6394/com.cwj.twoday E/ViewGroup-onInterceptTouchEvent: 按下
2019-03-14 17:48:52.304 6394-6394/com.cwj.twoday E/ViewGroup-onTouchEvent触摸: 按下
2019-03-14 17:48:52.379 6394-6394/com.cwj.twoday E/dispatchTouchEvent-分发: 松开
2019-03-14 17:48:52.379 6394-6394/com.cwj.twoday E/ViewGroup-dispatchTouchEvent分发: 松开
2019-03-14 17:48:52.379 6394-6394/com.cwj.twoday E/ViewGroup-onTouchEvent触摸: 松开
执行顺序:父布局:dispatchTouchEvent→ViewGroup.dispatchTouchEvent→ViewGroup.onInterceptTouchEvent→ViewGroup.onTouchEvent
感谢这位大神 初识Android触摸事件传递机制
敲一遍。是对好的老师。