Android 事件分发机制

Android事件分发机制

假设有以下布局:
在这里插入图片描述
Activity里嵌套了两个ViewGroup,最下层的绿色ViewGroup1和中间层的红色ViewGoup2,最上层的是一个TextView控件。

相关函数:

public boolean dispatchTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)

1.ACTION_DOWN的消息传递流程

图1-1展示了在不拦截消息时,ACTION_DOWN消息的完整传递流程。
在这里插入图片描述

可以看到在Activity 、ViewGroup、TextView中都有dispatchTouchEvent函数和onTouchEvent函数。而对于ViewGroup而言,则多了一个onInterceptTouchEvent函数。

1.1 不包含onInterceptTouchEvent函数的ACTION_DOWN消息流程传递
1.1.1 dispatchTouchEvent返回值简介
  • 默认的super.dispatchTouchEvent
  • 返回 true
  • 返回 false

dispatchTouchEvent函数采用默认处理方式情况下的消息传递流程,这种情况我们成为正常的消息传递流程,如图1-1-1所示:
在这里插入图片描述

1.1.2 dispatchTouchEvent函数中返回true拦截消息

结论: 在dispatchTouchEvent中返回true拦截消息之后,消息会直接停止传递,后面的子控件都不会接收到这个消息。

图1-1-2-1 展示了在Activity的dispatchTouchEvent中返回true的消息传递流程:
在这里插入图片描述

图1-1-2-2 展示了在ViewGroup1的dispatchTouchEvent中返回true的消息传递流程:
在这里插入图片描述

图1-1-2-3 展示了在ViewGoup2的dispatchTouchEvent中返回true的消息传递流程:
在这里插入图片描述

图1-1-2-4 展示了在View的dispatchTouchEvent中返回true的消息传递流程:
在这里插入图片描述

通过这些流程可以看出:无论在哪个控件的dispatchTouchEvent函数中拦截消息,消息都会直接停止传递,后面的子控件都不会接收到这个消息。

1.1.3 dispatchTouchEvent函数中返回false拦截消息

结论:在dispatchTouchEvent函数中返回false拦截消息之后,消息并不会直接停止传递,而是向父控件的onTouchEvent函数回传。

图1-1-3-1展示了在TextView的dispatchTouchEvent函数中返回false时的消息传递流程:

在这里插入图片描述

图1-1-3-2展示了在ViewGoup2的dispatchTouchEvent函数中返回了false时的消息传递流程:

在这里插入图片描述

图1-1-3-3展示了在ViewGroup1的dispatchTouchEvent函数中返回了false时的消息传递流程:
在这里插入图片描述

图1-1-3-4展示了在Activity的dispatchTouchEvent函数中返回false时的消息传递流程:
在这里插入图片描述

1.1.4 在onTouchEvent函数中拦截ACTION_DOWN消息

在onTouchEvent函数中,默认返回的是false,即不拦截;当返回true时,表示拦截。

结论:无论在哪个控件的onTouchEvent函数中拦截ACTION_DOWN消息,即返回true时,消息都会直接停止传递,后面的父控件都不会接收到这个消息。

需要注意的是,onTouchEvent函数的拦截效果看起来与dispatchTouchEvent函数返回true时的拦截效果是一致的,但仔细观察会发现,dispatchTouchEvent函数中的消息是从Activity向TextView传递,而onTouchEvent函数中的消息是从TextView向Activity回传的。

图1-1-4-1 展示了在TextView的onTouchEvent函数中返回true时的消息传递流程
在这里插入图片描述

图1-1-4-2 展示了在ViewGroup的onTouchEvent函数中返回true时的消息传递流程
在这里插入图片描述

总结

  • dispatchTouchEventonTouchEvent函数一旦返回true拦截消息,ACTION_DOWN消息就会停止传递,正常流程下的后续节点都不会收到ACTION_DOWN消息了。
  • dispatchTouchEvent函数返回false时,首先会拦截诶ACTION_DOWN消息向其子控件中传递,然后将消息向其父控件的onTouchEvent函数中继续回传。
1.2 onInterceptTouchEvent函数的ACTION_DOWN消息传递流程
1.2.1 onInterceptTouchEvent函数的作用

只有ViewGroup具有onInterceptTouchEvent函数,Activity和View中都没有。

顾名思义,onInterceptTouchEvent就是一个拦截过滤器。每个ViewGroup每次在做消息分发的时候,都会问一问拦截器要不要拦截(也就是问问自己这个事件要不要自己来处理)。如果要自己处理,那么就在onInterceptTouchEvent函数中返回true,这样就会将事件交给自己的onTouchEvent函数处理了,如果不拦截就继续往子控件处理。默认其是不拦截的。

1.2.2在ViewGroup的onInterceptTouchEvent函数中拦截ACTION_DOWN消息

图1-2-2-1 展示了在ViewGoup2的onInterceptTouchEvent函数中拦截消息
需要注意的是,在图中没有标注return true时,其他直接流向的箭头全部表示返回false,即在正常的不拦截情况下的消息流向

可以看到,在ViewGroup2的onInterceptTouchEvent函数中拦截了消息以后,函数直接将消息传递到ViewGroup2的onTouchEvent函数中,因为没有任何一个onTouchEvent函数返回true拦截消息,所以消息会一直流向Activity的onTouchEvent函数并停止传递。

图1-2-2-2 展示了在ViewGroup2的onInterceptTouchEvent函数中拦截消息
在这里插入图片描述

图1-2-2-3 展示了在ViewGroup2的onInterceptTouchEvent和onTouchEvent函数中拦截消息
在这里插入图片描述

总结

总结

  • 若在dispatchTouchEvent和onTouchEvent函数中返回true拦截消息的话,会直接将消息截断,后续节点将不会收到ACTION_DOWN消息。
  • 若在onInterceptTouchEvent函数中返回true拦截消息的话,只会改变ACTION_DOWN消息的正常流向,消息会直接流到自己的onTouchEvent函数中,并不会截断消息。
  • 若在dispatchTouchEvent函数中返回false拦截消息,同样会改变ACTION_DOWN消息的正常流向,消息会直接流向其父控件的onTouchEvent函数中,同样不会截断消息。
  • 一般我们在拦截消息时,都是共同使用onInterceptTouchEvent和onTouchEvent函数的,通过在onInterceptTouchEvent函数中返回true,将ACTION_DOWN消息流向自己的onTouchEvent函数中,然后在该onTouchEvent函数中返回true拦截消息。

2.ACTION_MOVE和ACTION_UP的消息传递流程

在这部分的消息传递流程中,红色表示ACTION_DOWN消息的传递,蓝色表示ACTION_MOVE/ACTION_UP消息的传递。

2.1 在dispatchTouchEvent函数中返回true拦截消息后的消息传递流程

结论:在dispatchTouchEvent函数中返回true拦截消息之后,ACTION_MOVE消息的流向与ACTION_DOEN消息的流向完全相同,消息会直接停止传递,后面的子控件都不会接受到这个消息。

图2-1-1 展示了在TextView的dispatchTouchEvent函数中返回true的消息传递:
在这里插入图片描述

图2-1-2 展示了在ViewGroup2的dispatchTouchEvent函数中返回true的消息传递:
在这里插入图片描述

图2-1-3 展示了在ViewGroup1的dispatchTouchEvent函数中返回true的消息传递:
在这里插入图片描述

图2-1-4 展示了在Activity的dispatchTouchEvent函数中返回true的消息传递:
在这里插入图片描述

2.2 传递到onTouchEvent函数后的ACTION_MOVE消息

从ACTION_DOWN消息的传递流程可以看出,只有在dispatchTouchEvent函数中返回true时,消息才会停止传递,而无论是dispatchTouchEvet函数返回false或者通过onInterceptTouchEvent函数拦截消息,消息最终都会流到onTouchEvent函数中。

结论:

  • 一旦ACTION_DOWN消息流入到onTouchEvent函数,假使其最终会被控件A的onTouchEvnet函数消费,即在控件A的onTouchEvent函数中返回了true,那么ACTION_MOVE消息在dispatchTouchEvent这条线上只会传递到控件A的dispatchTouchEvent函数中,然后直接传递到控件A的onTouchEvent函数中。
2.2.1 正常情况下的ACTION_MOVE消息传递流程

正常情况也就是任何函数都采用默认的方式执行的情况,也就是在所有函数都不拦截消息的情况下,ACTION_MOVE消息传递流程如图2-2-1所示:
在这里插入图片描述

可以看到ACTION_DOWN完整地走完了所有函数,最终流入到Activity的onTouchEvent函数,因此ACTION_MOVE消息的流向就是先流到Activity的dispatchTouchEvent函数中,然后直接流到Activity的onTouchEvent函数中后消失。
对应前面的结论,这里的Activity就是控件A。

2.2.2 当在onTouchEvent函数中拦截ACTION_DOWN消息

图2-2-2展示了在ViewGroup2的onTouchEvent函数中返回true的ACTION_DOWN和ACTION_MOVE的消息传递流程:
在这里插入图片描述

可以看到ACTION_MOVE消息也是从Activity流到ViewGroup2的diapatchTouchEvent函数中,最终流入到ViewGroup2的onTouchView函数中。
对应前面的结论,这里的ViewGroup2就是控件A。

图2-2-2-1展示了在TextView的dispatchTouchEvent函数返回false,在ViewGroup1的onTouchEvent函数中返回true拦截消息时,ACTION_MOVE消息的传递流程:
在这里插入图片描述

可以看到ACTION_MOVE消息也是从Activity流到ViewGroup1的diapatchTouchEvent函数中,最终流入到ViewGroup1的onTouchView函数中。
对应前面的结论,这里的ViewGroup1就是控件A。

图2-2-2-2展示了在ViewGroup2的onInterceptTouchEvent函数中返回true拦截消息,在ViewGroup1的onTouchEvent函数中返回true消费消息时,ACTION_MOVE消息的传递流程:
在这里插入图片描述

可以看到,虽然ACTION_DOWN消息的流向与前面流程不同,但是ACTION_MOVE消息的流向却还是从Activity流到ViewGroup1的diapatchTouchEvent函数中,最终流入到ViewGroup1的onTouchView函数中。

总结
  • 在dispatchTouchEvent函数中返回true拦截消息后,ACTION_MOVE消息的流向与ACTION_DOWN消息的流向完全相同,消息会直接停止传递,后面的子控件都不会接受到这个消息。
  • 无论ACTION_DOWN消息的流向是怎样的,只要最终流到onTouchEvent函数中就行。假使控件A最终在onTouchEvent函数中返回true消费了ACTION_DOWN消息,那么ACTION_MOVE消息的流向就是先流到控件A的dispatchTouchEvent函数中,最终流到控件A的onTouchEvent函数中,进而消息停止传递。
2.3 在ACTION_MOVE消息到来时拦截消息

前面讲到的都是正常的拦截消息的情况,即在ACTION_DOWN消息到来时就进行拦截。但如果我们把拦截动作推后,在ACTION_MOVE消息到来时再进行拦截,情况会如何?

2.3.1 注意事项

为了保证在ACTION_MOVE消息到来时能够拦截到消息,我们必须保证ACTION_MOVE消息能够经过该控件的disPatchTouchEvent或onInterceptTouchEvent函数。

2.3.2 ACTION_MOVE消息拦截初探

图2-3-2-1展示了在dispatchTouchEvent这条线上不做拦截,仅在TextView的onTouchEvent函数中返回true消费了消息时的消息传递流程:
在这里插入图片描述

可以看到这里ACTION_DOWN和ACTION_MOVE消息的传递流程完全相同。

我们在ViewGroup1的onInterceptTouchEvent函数中将代码改为如下这样:

public class ViewGroup1 extends LinearLayout{
	...
	@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    	switch(ev.getAction()){
    		case ACTION_MOVE:
    			return true;
    	}
    	return super.onInterceptTouchEvent(ev);
    }
}

即在消息ACTION_DOWN到来时不拦截,在ACTION_MOVE到来时进行返回true的拦截。这种情况的消息传递流程如图2-3-2-2所示:
在这里插入图片描述

- 红线: 这条线表示ACTION_DOWN消息的传递流程,也就是在TextView的OnTouchEvent函数中返回true消费消息时的传递流程。

绿线 :这条线表示ACTION_MOVE消息第一次传递时的流向情况。这里需要知道的是ACTION_MOVE消息会多次传递。这里是第一次的流向情况。

本来消息依然会从Activity的dispatchTouchEvent函数流向子控件,但是在到达ViewGroup1的onInterceptTouchEvent函数时,消息被拦截了。到这里,这次的ACTION_MOVE消息就没有了,变成了ACTION_CANCEL消息继续向子控件传递,一直传递到ACTION_MOVE消息原本要传递到的位置,通知所有被截断的子控件,它们的消息被取消了,后续不会再有消息传递过来,后续的ACTION_MOVE/ACTION_UP也不会再经过被截断的子控件了,即ViewGroup2以及View的dispatachTouchEvent和onTouchEvent函数都不会再接受到消息。
当我们收到ACTION_CANCEL消息时,就表示后续不再获得消息,一般需要像处理ACTION_UP消息一样处理该消息,执行控件归位等操作。

蓝线:这条线表示消息被截断之后的ACTION_MOVE/ACTION_UP消息的流向。可以看到,这时的ACTION_MOVE消息的流向与正常情况下ViewGroup1的onInterceptTouchEvent函数拦截ACTION_DOWN消息时ACTION_MOVE消息的流向是完全相同的。

2.3.3 在dispatchTouchEvent函数中拦截ACTION_MOVE消息
2.3.3.1 在ViewGroup2的dispatchTouchEvent函数中返回true拦截ACTION_MOVE消息:
public class ViewGroup2 extends LinearLayout{
	...
	@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    	switch(ev.getAction()){
    		case ACTION_MOVE:
    			return true;
    	}
    	return super.dispatchTouchEvent(ev);
    }
}

这种情况下的消息传递流程如图2-3-3-1所示:
在这里插入图片描述

- 红线: 这条线表示ACTION_DOWN消息的传递流程,也就是在TextView的OnTouchEvent函数中返回true消费消息时的传递流程。

绿线 :这条线表示ACTION_MOVE消息的传递流程。需要注意的是这里的ACTION_MOVE消息传递流程中没有第几次的区别,每次消息都直接在ViewGroup2的dispatchTouchEvent函数中被截断。这里没有发出ACTION_CANCEL消息,而是消息直接被截断了,而且也不会向onTouchEvent函数传递。

蓝线:这条线表示消息ACTION_UP消息的传递流程。可以看到,这时的ACTION_UP消息的流向与正常情况下ACTION_UP消息的流向是完全相同的。

2.3.3.1 在ViewGroup2的dispatchTouchEvent函数中返回false拦截ACTION_MOVE消息:
public class ViewGroup2 extends LinearLayout{
	...
	@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    	switch(ev.getAction()){
    		case ACTION_MOVE:
    			return false;
    	}
    	return super.dispatchTouchEvent(ev);
    }
}

这种情况下的消息传递流程如图2-3-3-2所示:
在这里插入图片描述

- 红线: 这条线表示ACTION_DOWN消息的传递流程,也就是在TextView的OnTouchEvent函数中返回true消费消息时的传递流程。

绿线 :这条线表示ACTION_MOVE消息的传递流程。需要注意的是这里的ACTION_MOVE消息传递流程中没有第几次的区别,每次消息在传递到ViewGroup2的dispatchTouchEvent函数中以后,就直接流到Activity的onTouchEvent函数中。事实上,无论你在哪个控件的dispatchTouchEvent函数中通过返回false拦截了ACTION_MOVE消息,之后消息都会直接流到Activity的onTouchEvent函数中。

蓝线:这条线表示消息ACTION_UP消息的传递流程。可以看到,这时的ACTION_UP消息的流向与正常情况下ACTION_UP消息的流向是完全相同的。

2.坐标系

2.1屏幕坐标系

如图2-1所示:
在这里插入图片描述

屏幕坐标系的起始位置就是屏幕的左上角,X轴向右为正,Y轴向下为正。

2.2View坐标系

如图2-2所示:
在这里插入图片描述

黑框表示屏幕,蓝色区块表示一级ViewGroup,它的子View是灰色区块所表示的二级ViewGroup,而二级ViewGroup又有一个子控件,这就是红色区块所表示的View控件。
View坐标系的坐标系原点在该View的父控件的左上角,即View坐标系是相对父控件而言的。

2.3 常用函数与View坐标系
getLeft、getTop、getRight、getBottom

这几个函数用于得到View控件左上角何右下角距离父View控件的距离。如图2-3所示:
在这里插入图片描述

需要注意的是,这4个函数获取的值是View原始状态时相对于父控件的距离,对View进行平移操作并不会改变这4个函数的返回值。

getWidth、getHeight

getWidth = getRight() - getLeft();
getHeight = getBottom() - getTop();

getX、getY

getX() = getLeft() + getTranslationX();
getY() = getTop() + getTranslationY();

getX、getY函数用于获取控件左上角点的实时位置。注意,view.getX和view.getY获取的坐标是相对于父控件而言的。

2.4 MotionEvent提供的函数
  • getX:获取点击事件距离控件左边的距离,即View坐标
  • getY:获取点击事件距离控件顶边的距离,即View坐标
  • getRawX:获取点击事件距离整个屏幕左边的距离,即绝对坐标
  • getRawY:获取点击事件距离整个屏幕顶边的距离,即绝对坐标

如图2-4所示:
在这里插入图片描述

判断当前触摸点是否在某个View的区域内
private boolean isPointOnViews(MotionEvent event) {
        boolean result = false;
        Rect rect = new Rect();
        for (int i = getChildCount()-1;i >= 0;i--) {
            View view = getChildAt(i);
            Log.d(TAG,"isPointOnViews===>view#getX="+view.getX()+",view#getY="+view.getY());
            int[] location = new int[2];
            // 获取控件在屏幕中的位置,返回的数组分别为控件左顶点的 x、y 的值
            view.getLocationOnScreen(location);
            Log.d(TAG,"isPointOnViews===>view#getLocationX="+location[0]+",view#getLocationY="+location[1]);
            Log.d(TAG,"isPointOnViews===>event#getX="+event.getX()+",view#getY="+event.getY());
            rect.set(
                    location[0],
                    location[1],
                    location[0]+view.getMeasuredWidth(),
                    location[1]+view.getMeasuredHeight());
            if(rect.contains((int)event.getRawX(),(int)event.getRawY())){
				// 标记被拖拽的child
                mDragView = view;
                result = true;
                break;
            }
        }
        return  result && currentState != State.DRAGGING;
    }

或者使用

private boolean isPointOnViews(MotionEvent event) {
        boolean result = false;
        Rect rect = new Rect();
        for (int i = getChildCount()-1;i >= 0;i--) {
            View view = getChildAt(i);
            Log.d(TAG,"isPointOnViews===>view#getX="+view.getX()+",view#getY="+view.getY());
            int[] location = new int[2];
            // 获取控件在屏幕中的位置,返回的数组分别为控件左顶点的 x、y 的值
            view.getLocationOnScreen(location);
            Log.d(TAG,"isPointOnViews===>view#getLocationX="+location[0]+",view#getLocationY="+location[1]);
            Log.d(TAG,"isPointOnViews===>event#getX="+event.getX()+",view#getY="+event.getY());
            rect.set((int) view.getX(), (int) view.getY(), (int) view.getX() + (int) view.getWidth()
                    , (int) view.getY() + view.getHeight());

          if (rect.contains((int) event.getX(), (int) event.getY())) {
               //标记被拖拽的child
               mDragView = view;
               result = true;
                break;
           }
        }
        return  result && currentState != State.DRAGGING;
    }

3.滑动冲突

3.1 详解requestDisallowInterceptTouchEvent(boolean disallowIntercept)函数

requestDisallowInterceptTouchEvent是ViewGroup中的函数,当子View不想父控件拦截消息的时候会调用requestDisallowInterceptTouchEvent(true)函数来通知父控件,让它不要拦截消息,使消息能够流向自己。

该函数有一个参数boolean disallowIntercept,表示是否禁止父控件拦截消息,参数值为true时,表示禁止父控件拦截消息;为false时,表示允许父控件拦截消息。

值得注意的是,要使requestDisallowInterceptTouchEvent(true)函数有效的前提是必须能够执行到它!如果父控件在获得ACTION_DOWN消息时就直接进行拦截的话,那么子控件将收不到任何消息,那么requestDisallowInterceptTouchEvent(true)函数也将不起作用。

3.2 requestDisallowInterceptTouchEvent函数的正确使用方法
3.2.1 在onInterceptTouchEvent函数中拦截ACTION_MOVE消息

首先需要消息能够流到子控件,这就要求父控件不拦截ACTION_DOWN消息,而只拦截ACTION_MOVE消息,也就是拦截消息的流程如图3-2-1所示:
在这里插入图片描述

即父控件的拦截消息代码如下:

public boolean onInterceptTouchEvent(MotionEvent event){
	switch(event.getAction()){
		case ACTION_MOVE:
			return true;
	}
	return super.onInterceptTouchEvent(event);
}

在这种情况下,在ACTION_DOWN消息到来时,消息就可以流到TextView的dispatchTouchEvent和onTouchEvent函数中了。而在TextView中,可以通过requestDisallowInterceptTouchEvent(true)来禁止父控件拦截消息。

public class CustomTextView extends TextView{
	...
	public boolean dispatchTouchevent(MotionEvent event){
		getParent().requestDisallowInterceptTouchEvent(true);
		return super.onInterceptTouchEvent(event);
	}

	public boolean onTouchEvent(MotionEvent event){
		getParent().requestDisallowInterceptTouchEvent(true);
	return super.onInterceptTouchEvent(event);
	}
}

在这种情况下,ACTION_MOVE消息并没有被拦截,而是直接传递给了顶层的CustomTextView,这样我们就实现了通过requestDisallowInterceptTouchEvent(true)来禁止父控件拦截消息的功能。
需要注意的是,在CustomTextView的所有父控件中消息都没有流到onInterceptTouchEvent函数中,这说明当我们通过requestDisallowInterceptTouchEvent(true) 来禁止父控件拦截消息时,该控件的所有父控件的onInterceptTouchEvent函数都将被跳过。

3.2.2 在dispatchTouchEvent函数中拦截ACTION_MOVE消息

我们在ViewGroup2的dispatchTouchEvent函数中拦截ACTION_MOVE消息,然后在CustomTextView的dispatchTouchEvent函数中添加禁止拦截消息的代码,会发现requestDisallowInterceptTouchEvent(true)函数无效,ACTION_MOVE消息并不会流向CustomTextView,而是在ViewGroup2的dispatchTouchEvent 函数中就停止了。

值得注意的是,requestDisallowInterceptTouchEvent 其仅能禁止onInterceptTouchEvent中的TouchEvent,因此在dispatchTouchEvent函数中拦截消息时,它是无效的。

总结
  • 要想使用requestDisallowInterceptTouchEvent(true);有效,不能在父控件中拦截ACTION_DOWN消息。
  • 在父控件的dispatchTouchEvent函数中拦截消息时,requestDisallowInterceptTouchEvent(true);将会失效。
  • 只有在父控件的onInterceptTouchEvent函数中拦截消息时,requestDisallowInterceptTouchEvent(true);才会有效。
  • 在通过requestDisallowInterceptTouchEvent(true);禁止父控件拦截消息时,所有父控件的onInterceptTouchEvent函数都将被跳过。
3.3 滑动冲突实战
3.3.1 滑动冲突类型
3.3.1.1 外层与内层的滑动方向不一致

比如外层只能横向滑动,内层只能纵向滑动。例如ViewPager内嵌ListView;

3.3.1.2 外层与内层的滑动方向一致

例如ViewPager内嵌横向的ListView。

3.3.2 解决思路
外部拦截法

点击事件都先经过父控件的拦截处理,如果父控件需要此事件就拦截,如果不需要就不拦截,让消息传递给子控件。
外部拦截法需要重写父控件的onInterceptTouchEvent函数,在内部进行相应的消息拦截即可,这种方法的伪代码如下:

public boolean onInterceptTouchEvent(MotionEvent event){
	boolean intercepted = false;
	switch(event.getAction){
		case MotionEvent.ACTION_DOWN:
			intercepted = false;
			break;
		case MotionEvent.ACTION_MOVE:
			if(父控件需要当前点击事件){
				intercepted = true}else{
				intercepted = false;
			}
			break;
		case MotionEvent.ACTION_UP:
			intercepted = false;
			break;
		default:
			break;
	}
	return intercepted;
}
内部拦截法

父控件不拦截任何消息,所有消息都传递给子控件,如果子控件需要此消息就直接消费掉,否则就交给父控件处理。

这种方法的伪代码如下:

public boolean dispatchTouchEvent(MotionEvent event){

	switch(event.getAction){
		case MotionEvent.ACTION_MOVE:
			if(自己需要当前点击事件){
				getParent().requestDisallowInterceptTouchEvent(true);
			}else{
				getParent().requestDisallowInterceptTouchEvent(false);
			}
			break;
		case MotionEvent.ACTION_UP:
			break;
		default:
			break;
	}
	return super.dispatchTouchEvent(event);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值