android控件层次嵌套关系(平级嵌套,父子嵌套)的视图关系,也就产生view(viewgroup)对触摸或者点击事件的消费关系,每一个控件都可以消费或者拒绝消费事件,在嵌套的布局中,关系可能更复杂些。android中的事件分发机制,保证我们想要的view获取到相应的事件。
view和viewgroup本质是做为view,但对于事件分发机制还是有很多区别,viewgroup可以做为view的载体,事件可能更复杂些。
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent ev);
当我们触摸到Activity中的控件时,分发流程如下
ViewGroup里的onInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.
ViewGroup里的onTouchEvent默认值是false。
View里的onTouchEvent返回默认值是true.这样才能执行多次touch事件。
举例:LinearLayout
当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由 dispatchTouchEvent 方法进行分发,
如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的
interceptTouchEvent 方法来决定是否要拦截这个事件,
如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。
在ViewGroup中
public boolean dispatchTouchEvent(MotionEvent ev){
....//其他处理,在此不管
View[] views=getChildView();
for(int i=0;iif(...){
if(views[i].dispatchTouchEvent(ev))
return true;
}
}
...//其他处理,在此不管
}
在View中
public boolean dispatchTouchEvent(MotionEvent ev){
....//其他处理,在此不管
return onTouchEvent(event);
}
决定touch事件是否向下处理
1、如果onInterceptTouchEvent()返回true,代表当前ViewGroup消费了事件,不再向下传递touch事件 。因此事件会被当前控件的onTouchEvent()处理
2、如果onInterceptTouchEvent()返回false,代表当前ViewGroup没有处理事件,处理向下传递给子view(或者子viewgroup),这样touch事件又到子view的onInterceptTouchEvent()。
LinearLayoutonInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.
onTouchEvent()用于处理事件(重点onTouch这个事件是从子控件回传到父控件的,一层层向下传),返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递。返回false,则向上传递给父控件,详细一点就是这个touch事件就给了父控件,那么后面的up事件就是到这里touch触发,不会在传给它的子控件。如果父控件依然是false,那touch的处理就给到父控件的父控件,那么up的事件处理都在父控件的父控件,不会触发下面的。
ViewGroup里的onTouchEvent默认值是false。
View里的onTouchEvent返回默认值是true.这样才能执行多次touch事件。
ViewGroup中
1、在ViewGroup中dispatchTouchEvent()中默认返回false
2、dispatchTouchEvent()中返回false后,进入到onInterceptTouchEvent()方法中,默认返回false
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
&& ev.getAction() == MotionEvent.ACTION_DOWN
&& ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
&& isOnScrollbarThumb(ev.getX(), ev.getY())) {
return true;
}
return false;
}
3、这样事件最终才传递给子vew的onTouchEvent()方法中。也就是定义的Linearlayout中的点击事件可以向下TextView,Button中传递
在View中
onTouchEvent默认返回true
也就是最终TextView,Button最终能够响应点击事件。
当点击红包区域时,红包区域响应事件,点击外部蓝色时,外部响应
点击红包区域时,响应事件,外层不响应
外部区域:
package com.example.touchdemo;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/**
* Created by yuxiaogang on 2017/4/5.
*/
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("------ll outer", "***dispatchTouchEvent--start ");
boolean b = super.dispatchTouchEvent(ev);
Log.i("------ll outer", "***dispatchTouchEvent--end "+b);
return true;
}
}
内部区域代码
package com.example.touchdemo;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/**
* Created by yuxiaogang on 2017/4/5.
*/
public class MyLinearLayoutInner extends LinearLayout {
public MyLinearLayoutInner(Context context) {
super(context);
}
public MyLinearLayoutInner(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("------ll inner", "***dispatchTouchEvent--start ");
boolean b = super.dispatchTouchEvent(ev);
Log.i("------ll inner", "***dispatchTouchEvent--start "+b);
return true;
}
}
参考博客
http://blog.csdn.net/xyz_lmn/article/details/12517911