【Android事件分发】从简单的onTouch理解Android事件分发
android,事件分发2016-06-07
简单的Touch其实里面有机制在处理着用户这一简单的操作,这个机制是一个规则,将事件一层层的传递下去。下面来看个实例:
下图是一个很常见的布局,Activity由LinearLayout直接填满,然后LinearLayout中只有一个Button。
现在用户对Button进行Touch操作。我们在Button做了Touch的监听。
若是只对button做监听,那么以下就是我们常见的写法
public class MainActivity extends AppCompatActivity {
private String TAG=MainActivity.class.getSimpleName();
private LinearLayout linearLayout;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
}
private void initView(){
linearLayout=(LinearLayout)findViewById(R.id.layout);
button=(Button)findViewById(R.id.button);
}
private void initEvent(){
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG, "事件传到 button ");
return false;
}
});
}
}
若是对LinearLayout就进行Touch监听呢?保留button监听,再加上个linearlayout的监听。如下:
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG, "事件传到 button ");
return false;
}
});
linearLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG, "事件传到 linearLayout ");
return false;
}
});
以上代码会有个现象:当linearlayout被触发时,button不一定被触发,而button被触发时,linearlayout一定会被触发。
那么为什么会这样呢?
因为button在linearlayout布局内。事件从上至下的分发下来。
我们可以仔细看看OnTouchListener。
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
重写时,都会默认返回false。那么返回false意味着什么呢?返回true又会发生什么事呢?
将linearlayout的touch返回值写为true,如下:
linearLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG, "事件传到 linearLayout ");
return true;
}
});
通过上面的代码,你会发现button的touch将不会被执行,而这一切的原因就是那个“true”!
现在我们重新理一下,整个事件执行的过程。
手指点击屏幕上的按钮,Activity中的一个dispatchTouchEvent(MotionEvent ev) 方法会一隧道的方式将事件传递给最外层View对应的dispatchTouchEvent(MotionEvent ev)方法,并且最后由View的dispatchTouchEvent(MotionEvent ev)对事件进行分发。
若 dispatchTouchEvent 返回的是true,那么事件将停止向下分发(这就是上面不执行button事件的原因)。表示当前View消费掉事件。
若 dispatchTouchEvent 返回的是false,可以分为两种情况,如下:
其他扩展
事件拦截:
在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:
如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的
onTouchEvent 进行处理; 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View
上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发; 如果
onInterceptTouchEvent 返回
super.onInterceptTouchEvent(ev),事件默认会被拦截,并将拦截到的事件交由当前 View 的
onTouchEvent 进行处理。
事件响应:
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:
如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View
向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回
false,这个事件就会“消失”,而且接收不到下一次事件。 如果返回了 true 则会接收并消费该事件。 如果返回
super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。