Android触摸手势的传递图解

前言:本篇博文主要分析关于onTouchEvent,dispatchTouchEvent和onInterceptTouchEvent这三个方法的作用和它们之间的关系,通过流程图来解释触摸事件(MotionEvent)是怎么在三个方法中传递的;

为了了解三个方法之间的关系,我们通过一个demo来分析他们之间的关系,demo主要内容为在一个activity上设置两个布局控件,一个为LinearLayout,一个是TextView,两个控件都自定义重写了他们的onTouchEvent、dispatchTouchEvent和onInterceptTouchEvent方法,并用logcat打印出各个方法相应的log标记,通过触摸控件后log的打印顺序就可知道他们的调用顺序了,通过调用顺序去分析事件的传递流程,如下图所示为activity的视图

其中红色区域为Textview的视图,底下绿色区域为LinearLayout的视图,最底下蓝色区域为activity的视图;下面贴上代码:

public class GestureDemo extends Activity {

	public final static String TAG = "GestureDemo";
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);	
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		
		Log.i(TAG,"Activity onTouchEvent. action="+getAction(event));
		return super.onTouchEvent(event);
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		
		Log.i(TAG,"Activity dispatchTouchEvent. action="+getAction(ev));
		return super.dispatchTouchEvent(ev);
	} 
}
public class MyLinearLayout extends LinearLayout {

	public MyLinearLayout(Context context) {
		super(context);
	}
	
    public MyLinearLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    
    public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    	super(context,attrs,defStyleAttr);
    }
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {

		Log.i(GestureDemo.TAG,"MyLinearLayout dispatchTouchEvent. action="+GestureDemo.getAction(ev));
		return super.dispatchTouchEvent(ev);
	}
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		Log.i(GestureDemo.TAG,"MyLinearLayout onInterceptTouchEvent. action="+GestureDemo.getAction(ev));
		return super.onInterceptTouchEvent(ev);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.i(GestureDemo.TAG,"MyLinearLayout onTouchEvent. action="+GestureDemo.getAction(event));
		return super.onTouchEvent(event);
	}
}
public class MyTextView extends TextView {

	public MyTextView(Context context) {
		super(context);
	}

	public MyTextView(Context context, AttributeSet attrs){
		super(context,attrs);
	}
	
	MyTextView(Context context, AttributeSet attrs, int defStyleAttr){
		super(context,attrs,defStyleAttr);
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		Log.i(GestureDemo.TAG,"MyTextView dispatchTouchEvent. action="+GestureDemo.getAction(event));
		return super.dispatchTouchEvent(event);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.i(GestureDemo.TAG,"MyTextView onTouchEvent. action="+GestureDemo.getAction(event));
		return super.onTouchEvent(event);
	}
}


注: 每一次屏幕触摸后的手势事件都是连续地由一个down事件、若干move事件和一个up事件组成,每次都必须是down事件先发生,最后一个是up事件;

触摸事件:每一个down事件、move事件或up事件都为一个独立的触摸事件;

手势事件:由一系列连续的触摸事件组成的一个完整的手势,比如单击手势事件为down-up, 滑动事件为down-move…move-up; 


下面通过逐个改变各个方法的返回值,分析它们之间的传递图;

一、 关于onTouchEvent事件

1.所有方法都返回父类的方法,即MotionEvent没有被子控件消耗掉,最终只有在activity的onTouchEvent消失掉(系统默认传递流程);

     

2. Activity的onTouchEvent方法返回true,其事件传递流程和上一个相同

.


3. MyLinearLayout的onTouchEvent返回true


4. MyTextView的onTouchEvent返回true;


总结:以上四张图中,只改动onTouchEvent的返回值,其他方法都调用父类方法,也就是传递流程都为系统默认的流程,没有人为干预,图1即是默认的系统流程,而图2,3,4通过改变onTouchEvent的返回值为true来终止事件的继续传递;从图中可知,当屏幕触摸发生时,down事件每次都是由系统先调用最底层的activity的dispatchTouchEvent事件,然后继续往上传递到最顶层控件,然后由onTouchEvent往下传递,按照默认传递顺序,如果哪个控件返回true,事件就在那个控件停止,即被这个控件消耗掉,如:activity和MyLinearLayout的onTouchEvent都返回true,那么事件只传递到MyLinearLayout的onTouchEvent,因为事件先经过MyLinearLayout的onTouchEvent,先被它截住了;而后续的move、up事件则会根据上个down事件最终在哪个控件被消耗掉,然后按照默认系统流程传递到该控件的dispatchTouchEvent后直接传递给自己的onTouchEvent,不会再往上层控件传递;


二、关于dispatchTouchEvent

  1. MyLinearLayout的dispatchTouchEvent返回true


2.   MyTextView的dispatchTouchEvent返回true


3.   MyLinearLayout的dispatchTouchEvent返回false


4. MyTextView的dispatchTouchEvent返回false


总结dispatchTouchEvent从方法名大约就可以知道其功能是分发触摸事件,该方法会根据它的返回值来决定事件要往哪个方向传递:

(1)若返回父类方法,则交由系统来决定,即为系统默认方向继续传递给上层控件的方法;

(2)若返回true,则不再继续传递,传递到这个方法为止,即这个方法消耗了事件;

(3)若返回false,事件传递到该方法后,事件退回到底下的父控件,继续往系统默认方向传递;如图8所示,MyTextView的dispatchTouchEvent返回false,事件退回到MyLinearLayout的onInterceptTouchEvent,继续往MyLinearLayout的onTouchEvent传递,即相当于以MyLinearLayout为最顶层控件;

三、关于onInterceptTouchEvent

1.MyLinearLayout的onInterceptTouchEvent返回true

总结:该方法只有ViewGroup的控件才会有,其父类的方法直接返回false,所以返回false就为图1中按默认方向传递了;该方法的作用就是拦截触摸事件,如果返回true,就是在当前控件拦截住触摸事件,传递给自己的onTouchEvent方法,再继续往底下控件传递给onTouchEvent,如果返回false或父类方法,就传递给它上面控件的dispatchTouchEvent


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值