源码总结
Android
事件分发传递到Acitivity后,总是先传递到ViewGroup
、再传递到View
。流程总结如下:(假设已经经过了Acitivity事件分发传递并传递到ViewGroup)
源码总结
核心方法总结
主要包括:dispatchTouchEvent()、onTouchEvent() 、onInterceptTouchEvent()总结如下
实例分析
1. 布局说明
布局层次
2. 测试代码
布局文件:activity_main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:id=“@+id/my_layout”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
xmlns:app=“http://schemas.android.com/apk/res-auto”
android:focusableInTouchMode=“true”
android:orientation=“vertical”>
<Button
android:id=“@+id/button1”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:text=“按钮1” />
<Button
android:id=“@+id/button2”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:text=“按钮2” />
核心代码:MainActivity.java
public class MainActivity extends AppCompatActivity {
Button button1,button2;
ViewGroup myLayout;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button)findViewById(R.id.button1);
button2 = (Button)findViewById(R.id.button2);
myLayout = (LinearLayout)findViewById(R.id.my_layout);
// 1.为ViewGroup布局设置监听事件
myLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(“TAG”, “点击了ViewGroup”);
}
});
// 2. 为按钮1设置监听事件
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(“TAG”, “点击了button1”);
}
});
// 3. 为按钮2设置监听事件
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(“TAG”, “点击了button2”);
}
});
}
}
3. 测试结果
// 点击按钮1,输出如下
点击了button1
// 点击按钮2,输出如下
点击了button2
// 点击空白处,输出如下
点击了ViewGroup
4. 结果分析
-
点击Button时,因为ViewGroup默认不拦截,所以事件会传递到子View Button,于是执行Button.onClick()。
-
此时ViewGroup. dispatchTouchEvent()会直接返回true,所以ViewGroup自身不会处理该事件,于是ViewGroupLayout的dispatchTouchEvent()不会执行,所以注册的onTouch()不会执行,即onTouchEvent() -> performClick() -> onClick()整个链路都不会执行,所以最后不会执行ViewGroup设置的onClick()里。
-
点击空白区域时,ViewGroup. dispatchTouchEvent()里遍历所有子View希望找到被点击子View时找不到,所以ViewGroup自身会处理该事件,于是执行onTouchEvent() -> performClick() -> onClick(),最终执行ViewGroupLayout的设置的onClick()
流程3:View的事件分发机制
从上面ViewGroup
事件分发机制知道,View
事件分发机制从dispatchTouchEvent()
开始
源码分析
/**
- 源码分析:View.dispatchTouchEvent()
*/
public boolean dispatchTouchEvent(MotionEvent event) {
if ( (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener != null &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
// 说明:只有以下3个条件都为真,dispatchTouchEvent()才返回true;否则执行onTouchEvent()
// 1. (mViewFlags & ENABLED_MASK) == ENABLED
// 2. mOnTouchListener != null
// 3. mOnTouchListener.onTouch(this, event)
// 下面对这3个条件逐个分析
/**
-
条件1:(mViewFlags & ENABLED_MASK) == ENABLED
-
说明:
-
- 该条件是判断当前点击的控件是否enable
-
- 由于很多View默认enable,故该条件恒定为true(除非手动设置为false)
*/
/**
-
条件2:mOnTouchListener != null
-
说明:
-
- mOnTouchListener变量在View.setOnTouchListener()里赋值
-
- 即只要给控件注册了Touch事件,mOnTouchListener就一定被赋值(即不为空)