android 事件处理

 

用到的例子工程介绍:在viewGroup中加入子view,即LinerLayout中存在一子view,在MyLinerLayout中重写了 dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

在MyTestView中重写了dispatchTouchEvent、onTouchEvent。

分别研究各种返回值对事件传递的路径影响。

MyLinerLayout.java


public class MyLinearLayout extends LinearLayout  implements View.OnClickListener,View.OnLongClickListener  {
	private final static String TAG = "TouchEvent";
	public MyLinearLayout(Context context, AttributeSet attrs) {
 
		super(context, attrs);
		// TODO Auto-generated constructor stub
		Log.v(TAG , "MyLinearLayout");
		//this.setOnClickListener(this);
		//this.setOnLongClickListener(this);
	}
	
	public void onClick(View v) {
		// TODO Auto-generated method stub
		Log.v(TAG ,  "MyLinearLayout onClick [" + "] test.................view:"+v.getId() );
	}
	
	@Override
	public boolean onLongClick(View v) {
		// TODO Auto-generated method stub
		boolean b = true;
		Log.v(TAG ,  "MyLinearLayout onLongClick [" + "] test.................view:"+v.getId() +"return :"+b);
		return true;
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
 
		switch (action) {
 
		case MotionEvent.ACTION_DOWN:
 
			Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_DOWN");
 
			break;
 
		case MotionEvent.ACTION_MOVE:
 
			Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_MOVE");
			return false;
			//break;
 
		case MotionEvent.ACTION_UP:
 
			Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_UP");
 
			break;
 
		case MotionEvent.ACTION_CANCEL:
 
			Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_CANCEL");
 
			break;
 
		}
//        	Log.v(TAG ,  "dispatchTouchEvent "+super.dispatchTouchEvent(ev));
		boolean b = super.dispatchTouchEvent(ev);
		//boolean b = false;
		Log.v(TAG ,  "MyLinearLayout --dispatchTouchEvent ["+action+ "] test.................return:"+b);
		return b;
	}
 
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
 
		int action = ev.getAction();
 
		switch (action) {
 
		case MotionEvent.ACTION_DOWN:
 
			Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_DOWN");
 
			break;
 
		case MotionEvent.ACTION_MOVE:
 
			Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_MOVE");
 
			break;
 
		case MotionEvent.ACTION_UP:
 
			Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_UP");
 
			break;
 
		case MotionEvent.ACTION_CANCEL:
 
			Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_CANCEL");
 
			break;
 
		}
		//boolean b = super.onInterceptTouchEvent(ev);
		boolean b = true;
		Log.v(TAG ,  "MyLinearLayout --onInterceptTouchEvent ["+action+ "] test.................return: "+b);
		return b;
 
	}
 
	@Override
    public boolean onTouchEvent(MotionEvent ev) {
 
        int action = ev.getAction();
        //boolean  b = super.onTouchEvent(ev);
        boolean b = true;
        switch (action) {
 
        case MotionEvent.ACTION_DOWN:
 
            Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_DOWN");
 
            break;
 
        case MotionEvent.ACTION_MOVE:
 
            Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_MOVE");
 
            break;
 
        case MotionEvent.ACTION_UP:
 
            Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_UP");
 
            break;
 
        case MotionEvent.ACTION_CANCEL:
 
            Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_CANCEL");
 
            break;
 
        }
       
        Log.v(TAG ,  "MyLinearLayout --onTouchEvent ["+action+ "] test.................return: "+b);
        return b;
    }


}

TextView.java

package com.lee.stony;
 
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.TextView;
import android.view.View;

public class MyTestView extends TextView{
 
	public static final String TAG = "TouchEvent";
 
	public MyTestView(Context context, AttributeSet attrs) {
 
		super(context, attrs);
		// TODO Auto-generated constructor stub
		Log.v(TAG, "MyTestView");
		/*this.setOnClickListener(this);
		this.setOnLongClickListener(this);*/
	}
	
	/*@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		Log.v(TAG ,  "MyTestView onClick [" + "] test.................view:"+v.getId() );
	}
	
	@Override
	public boolean onLongClick(View v) {
		// TODO Auto-generated method stub
		boolean b = true;
		Log.v(TAG ,  "MyTestView onLongClick [" + "] test.................view:"+v.getId() +"return :"+b);
		return true;
	}
*/
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
 
		switch (action) {
 
		case MotionEvent.ACTION_DOWN:
 
			Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_DOWN");
 
			break;
 
		case MotionEvent.ACTION_MOVE:
 
			Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_MOVE");
 
			break;
 
		case MotionEvent.ACTION_UP:
 
			Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_UP");
 
			break;
 
		case MotionEvent.ACTION_CANCEL:
 
			Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_CANCEL");
 
			break;
 
		}
		boolean b = super.dispatchTouchEvent(ev);
		//boolean b = true;
		Log.v(TAG ,  "MyTestView dispatchTouchEvent ["+action+ "] test.................return:"+b);
		return b;
	}
 
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		boolean b = super.onTouchEvent(ev);
		int action = ev.getAction();
 
		switch (action) {
 
		case MotionEvent.ACTION_DOWN:
 
			Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_DOWN");
 
			break;
 
		case MotionEvent.ACTION_MOVE:
 
			Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_MOVE");
 
			break;
 
		case MotionEvent.ACTION_UP:
 
			Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_UP");
 
			break;
 
		case MotionEvent.ACTION_CANCEL:
 
			Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_CANCEL");
 
			break;
 
		}
		
		//boolean b = true;
		Log.v(TAG ,  "MyTestView onTouchEvent ["+action+ "] test.................return:"+b);
		return b;
 
	}
 
}


 

1、 android中用于事件处理的方法和类主要有如下几种:

onTouchEvent

onInterceptTouchEvent//在viewgroup才有的方法,用于分发子view

dispatchTouchEvent 

 

实现View.OnClickListener 的onClick

实现View.OnLongClickListener 的 onLongClick

实现View.OnTouchClickListener 的 onTouch

 

说明:在事件处理中,其实我们一般遇到事件有3中,分别是down、move、up,其中move事件在一个操作中(这里说的一个操作就是用户与屏幕的交互,即由down到up的动作序列)可能会发生多次,但是,我们认为一个动作序列会包含以上三种事件,因此,在事件处理中就是要处理好这个过程,而最重要的就是down事件,这是一个动作序列的起始,没有down谈不上后面的事件了。所以,我们把消耗down事件的类当做是这个动作序列的最终载体。

2、 各种返回值的含义和作用

(1)dispatchTouchEvent()

返回值

作用

True

继续接受动作序列中的后续事件,如move、move、up

False

不接受动作序列中的后续事件,因此本次后续操作不起作用,如:down后返回false,则move和up都不会被接受,只能接受下个动作。这里为什么特别指定的down事件呢,因为如果down返回true,说明后续事件会被传递于此,但是move返回false呢?哈哈,这个就不会影响了,因此说down才是关键

总结:此方法一般用于初步处理事件,因为动作是由此分发,所以通常会调用super.dispatchTouchEvent。这样就会继续调用onInterceptTouchEvent,再由onInterceptTouchEvent决定事件流向。

例子:

 

 

当在DispatchTouchEvent中调用了super.dispatchTouchEvent,则会继续向下执行到onInterceptTouchEvent方法。

 

(2)onInterceptTouchEvent():

返回值

作用

True

事件会传递到自己的onTouchEvent()

False

传递到下一个view的dispatchTouchEvent()

例子1:

方法

返回值

说明

 

MyLinerLayout

dispatchTouchEvent

True

调用super. dispatchTouchEvent

onInterceptTouchEvent

true

True 则调用自己的onTouchEvent

onTouchEvent

true

True 则后续动作序列直接发到此处,不经过onInterceptTouchEvent

MyTestView

dispatchTouchEvent

True

这里因为MyLinerLayout. onInterceptTouchEvent返回true,因此不会传递于此

onTouchEvent

True

 

图:点击父和子view效果一样

说明:Down事件在MyLinerLayout.onInterceptTouchEvent()后返回true,则传递到onTouchEvent,当其返回true时,动作序列的后续事件不会再通过onInterceptTouchEvent了,而是在dispatchTouchEvent中直接传递于onTouchEvent。注意:此处点击MylinerLayout和MytestView效果一致。

 

例子2:

方法

返回值

说明

 

MyLinerLayout

dispatchTouchEvent

True

调用super. dispatchTouchEvent

onInterceptTouchEvent

False

False则点击非子view(没有子view处理)时会传递于onTouchEvent,但是如果点击MyTestView,即它的子view,则会传递到子view的onDispatchTouchEvent

onTouchEvent

true

True 则后续动作序列直接发到此处,不经过onInterceptTouchEvent

MyTestView

dispatchTouchEvent

True

调用super. dispatchTouchEvent

onTouchEvent

True

 

 

图1:点击父view

说明:onInterceptTouchEvent返回false本应该传给下个子view的dispatchTouchEvent,但是,点击的是父view,因此不存在子view而直接传给自己的onTouchEvent,并且onTouchevent返回true,所以,后续事件不经过onInterceptTouchEvent(确定了自己要处理就不必再考虑如何分发给子view了)

图2:点击子view

说明:可以看到虽然MytestView.onTouchEvent接受并返回了true,事件还是需要经过MyLinerLayout.onInterceptTouchEvent(这是一个通道,分发给子view就要经过),

 

总结:onInterceptTouchEvent要做的就是确定事件传递到哪个子view,如果返回false,但是又没有子view处理(因为根本就没有点击到子view),就自己处理了,而自己在onTouchEvent处理的后续事件就不必经过onInterceptTouchEvent了,它是判断传递给子view的,都不是子view处理,就不用经过了。(以上说明,android事件处理机制中,明确谁要处理,确定后就会形成一条通道,后续事件就走这条通道吧)

 

 

 

注意:正常情况下dispatchTouchEvent会调用super. dispatchTouchEvent,并将其作为返回值,其实这会传递下一个接受者,让下个接受者处理并将最终的处理的返回值(在最后的onTouchEvent中,让其决定是否还需要接受后续动作序列)作为自己的返回值。而下个调用者即是onInterceptTouchEvent,不过它只是决定分发方向的,所以它的返回值对dispatchTouchEvent不影响,而onInterceptTouchEvent也可以调用super. onInterceptTouchEvent,但是这总返回false,即总希望让子view来处理。一般不用

 

 

(2)onTouchEvent():

返回值

作用

True

事件由自己处理消耗,后续动作序列让其处理,因为在down事件时确定了路径,因此后续事件就不会迷路了

False

自己不消耗事件了,向上返回让其他来父view的onTouchEvent接受处理吧

例子3:

方法

返回值

说明

 

MyLinerLayout

dispatchTouchEvent

 

调用super. dispatchTouchEvent,根据不同的view的返回值会不同,不过此处总是返回false

onInterceptTouchEvent

False

False则点击非子view(没有子view处理)时会传递于onTouchEvent,但是如果点击MyTestView,即它的子view,则会传递到子view的onDispatchTouchEvent

onTouchEvent

False

False 则后续动作序列一般不发到此处(要看dispatchTouchEvent的返回值,如果其使用super. dispatchTouchEvent,会使用本方法的返回值,即false)。

MyTestView

dispatchTouchEvent

 

调用super. dispatchTouchEvent,也会返回false

onTouchEvent

False

 

 

图1:点击父view

说明:当传递到自己的onTouchEvent时,返回false,而dispatchTouchEvent也使用这返回值false,因此,本次操作的后续动作序列就不会再传递了,没有view处理后续的move、up。除非再次点击才会有事件传递,不过,结果跟上图一样,处理了down返回false就没下文了。

 

 图2:点击子view


说明:当事件流向MytestView.onTouchEvent时,返回了false,说明自己不处理了,让父view的onTouchEvent处理吧,而父view也返回false不处理,就继续向上抛,直到消失,当down事件没有被view确认处理,则后续动作序列也就不会再传递了。

 

例子4:跟例子3差不多,只是MyLinerLayout.onTouchEvent返回true

方法

返回值

说明

 

MyLinerLayout

dispatchTouchEvent

 

调用super. dispatchTouchEvent,根据不同的view的返回值会不同,不过此处总是返回false

onInterceptTouchEvent

False

False则点击非子view(没有子view处理)时会传递于onTouchEvent,但是如果点击MyTestView,即它的子view,则会传递到子view的onDispatchTouchEvent

onTouchEvent

True

True 则后续动作序列直接发到此处,不经过onInterceptTouchEvent

MyTestView

dispatchTouchEvent

 

调用super. dispatchTouchEvent,也会返回false

onTouchEvent

False

事件没有被消耗,传给父view的onTouchEvent

注意:这里点击父view会跟例子2中图1一样,因为,事件根本没有传递到子view的机会。

图1:点击子view

说明:当到达MyTestView. onTouchEvent时返回false,则传递给父view的onTouchEvent,而其返回true,说明就让其处理吧,所以后续动作序列直接发到此处。

 

总结:onTouchEvent被认为是动作的最终处理的函数,不管是父view还是子view处理,只要onTouchEvent消耗了事件(返回true),则认为后续动作序列的通路已经确定,否则,向上处理,直到消失。

 

3、前面说的都是在view或viewgroup的重写的处理事件的方法,但是,如果注册了监听器后事件又是如何走呢?

 

  • 9
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值