本文转载自:http://blog.youkuaiyun.com/wdong_love_cl/article/details/51477607
先讲View:
只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法,看下该函数的实现:
- public boolean dispatchTouchEvent(MotionEvent event) {
- if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
- mOnTouchListener.onTouch(this, event)) {
- return true;
- }
- return onTouchEvent(event);
- }
- public boolean onTouchEvent(MotionEvent event) {
- ...
- if (((viewFlags & CLICKABLE) == CLICKABLE ||
- (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- ...
- performClick();
- break;
- case MotionEvent.ACTION_DOWN:
- break;
- case MotionEvent.ACTION_CANCEL:
- break;
- case MotionEvent.ACTION_MOVE:
- break;
- }
- return true;
- }
- return false;
- }
- public boolean performClick() {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
- if (mOnClickListener != null) {
- playSoundEffect(SoundEffectConstants.CLICK);
- mOnClickListener.onClick(this);
- return true;
- }
- return false;
- }
总结一下,总的调用顺序:
dispatchTouchEvent-->onTouch()[需要返回false才会继续往下]-->onTouchEvent()[需要控件是clickable才会继续往下走]-->onClick()。
再看看ViewGroup的事件分发,ViewGroup是什么呢?
ViewGroup就是一组View的集合,它包含很多的子View和子VewGroup,是Android中所有布局的父类或间接父类,像LinearLayout、RelativeLayout等都是继承自ViewGroup的。但ViewGroup实际上也是一个View,只不过比起View,它多了可以包含子View和定义布局参数的功能。
面前说点击某一个控件,会调用到该控件的dispatchTouchEvent方法,实际是这样的:当你点击了某个控件,首先会去调用该控件所在布局的dispatchTouchEvent方法,然后在布局的dispatchTouchEvent方法中找到被点击的相应控件,再去调用该控件的dispatchTouchEvent方法。
下面来看下ViewGroup的dispatchTouchEvent()方法的实现吧:
- public boolean dispatchTouchEvent(MotionEvent ev) {
- ...
- if (disallowIntercept || !onInterceptTouchEvent(ev)) {
- final int count = mChildrenCount;
- for (int i = count - 1; i >= 0; i--) {
- final View child = children[i];
- ...
- if (child.dispatchTouchEvent(ev)) {
- mMotionTarget = child;
- return true;
- }
- }
- }
- ...
- if (target == null) {
- ...
- return super.dispatchTouchEvent(ev);
- }
- ...
- return target.dispatchTouchEvent(ev);
- }
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return false;
- }
看一个例子:
- public class MyLayout extends LinearLayout {
- public MyLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return true;
- }
- }
- myLayout.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- Log.d("TAG", "myLayout on touch");
- return false;
- }
- });
- button1.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Log.d("TAG", "You clicked button1");
- }
- });
该例子中,MyLayout布局里面包含了一个button1,并且为myLayout和button1都添加了OnTouchListener,如果我们重写的onInterceptTouchEvent返回true,那么touch事件就被myLayout拦截了,不会传到button1上面,反之会则会传到button1上面,当然点击空白区域还是会被myLayout捕获的。
下面用一张图来总结下这个流程:
在解决事件冲突中的运用:
比如scrollview嵌套viewpager导致的滑动冲突
有两种解决方法:
1、重写scrollview类的onInterceptTouchEvent方法,如果发现是水平滑动的话,那就在该方法内返回false,这样就不拦截viewpager了,会执行viewpager的onTouchEvent方法;
2、重写viewpager中的onTouchEvent方法,如果发现水平滑动就设置getParent().requestDisallowInterceptTouchEvent(true)来通知父控件不要拦截事件,如果是竖直滑动就设置为false。
859

被折叠的 条评论
为什么被折叠?



