迅速理解Android事件传递

本文通过自定义ViewGroup和Button的触控事件处理方法,详细解析了Android触控事件的传递流程。包括dispatchTouchEvent、onInterceptTouchEvent、onTouch、onTouchEvent及onClick等方法的作用及其之间的交互方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    最近学习 Android,感觉Android事件传递机制很有意思,搞懂这个基础知识点是必须的,于是收集资料,做个Demo加深印象,记录之。

    Demo比较简单,一个ViewGroup上放置一个按钮。

    自定义VieGroup继承自LinearLayout:

 

package com.example.mydispatchtouchevent;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.LinearLayout;

public class MyView extends LinearLayout implements OnClickListener,OnTouchListener{

	public MyView(Context context) {
		super(context);
		setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		Log.i("TAG","viewgroup_doClick");
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		Log.i("TAG","viewgroup_onTouch="+event.getAction());
		return false;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.i("TAG","viewgroup_onTouchEvent="+event.getAction());
		return super.onTouchEvent(event);
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		Log.i("TAG","viewgroup_dispatchTouchEvent="+event.getAction());
		return super.dispatchTouchEvent(event);
	}
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		Log.i("TAG","viewgroup_onInterceptTouchEvent");
		return super.onInterceptTouchEvent(ev);
	}
	
}

   

 

   自定义Button:

 

package com.example.mydispatchtouchevent;

import android.content.Context;
import android.util.Log;
import android.widget.Button;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.View.OnClickListener;

public class MyButton extends Button implements OnTouchListener,
		OnClickListener {

	public MyButton(Context context) {
		super(context);
		setOnTouchListener(this);
		setOnClickListener(this);
		this.setText("测试");
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		Log.i("TAG", "button_onTouch=" + event.getAction());
		return false;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.i("TAG", "button_onTouchEvent=" + event.getAction());
		return super.onTouchEvent(event);
		//return false;
	}

	@Override
	public void onClick(View v) {
		Log.i("TAG", "button_doClick");
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		Log.i("TAG", "button_dispatchTouchEvent=" + event.getAction());
		return super.dispatchTouchEvent(event);
	}
}

 

 

    Activity:

package com.example.mydispatchtouchevent;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends Activity {
	Button myBtn;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		ViewGroup viewGroup = new MyView(this);
		Button button = new MyButton(this);
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.WRAP_CONTENT,
				LinearLayout.LayoutParams.WRAP_CONTENT);		
		button.setLayoutParams(params);
		viewGroup.addView(button);
		setContentView(viewGroup);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.i("TAG", "Activity_onTouchEvent=" + event.getAction() + " / "
				+ "event=" + event.hashCode());
		return super.onTouchEvent(event);
	}
}

    

 

    给自定义ViewGroup实现dispatchTouchEvent,onInterceptTouchEvent,onTouch,onTouchEvent,onClickButton实现dispatchTouchEvent,onTouch,onTouchEvent,onClick,Activity上实现onTouchEvent。

 

  点击按钮,运行结果:

 

02-16 02:45:18.209: I/TAG(2535): viewgroup_dispatchTouchEvent=0
02-16 02:45:18.209: I/TAG(2535): viewgroup_onInterceptTouchEvent
02-16 02:45:18.209: I/TAG(2535): button_dispatchTouchEvent=0
02-16 02:45:18.209: I/TAG(2535): button_onTouch=0
02-16 02:45:18.209: I/TAG(2535): button_onTouchEvent=0
02-16 02:45:18.313: I/TAG(2535): viewgroup_dispatchTouchEvent=1
02-16 02:45:18.313: I/TAG(2535): viewgroup_onInterceptTouchEvent
02-16 02:45:18.313: I/TAG(2535): button_dispatchTouchEvent=1
02-16 02:45:18.313: I/TAG(2535): button_onTouch=1
02-16 02:45:18.313: I/TAG(2535): button_onTouchEvent=1
02-16 02:45:18.321: I/TAG(2535): button_doClick

    顺序一目了然,viewgroup_dispatchTouchEvent先得到event,然后是viewgroup_onInterceptTouchEvent,接下来就把event转交给button,ACTION_DOWN和ACTION_UP各走一遍后,最后执行button_doClick。

  这些方法的游戏规则是:如果返回true,event被消化了,不再传递;如果返回false,event交给下一位继续。在button_onTouchEvent中返回了true,事件传递就到此为止,其中button_doClick是在button_onTouchEvent中调用。

  button_onTouchEvent修改为:

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.i("TAG", "button_onTouchEvent=" + event.getAction());
		//return super.onTouchEvent(event);
		return false;
	}

  点击按钮:

02-16 03:02:38.213: I/TAG(2582): viewgroup_dispatchTouchEvent=0
02-16 03:02:38.213: I/TAG(2582): viewgroup_onInterceptTouchEvent
02-16 03:02:38.213: I/TAG(2582): button_dispatchTouchEvent=0
02-16 03:02:38.213: I/TAG(2582): button_onTouch=0
02-16 03:02:38.213: I/TAG(2582): button_onTouchEvent=0
02-16 03:02:38.213: I/TAG(2582): viewgroup_onTouchEvent=0
02-16 03:02:38.317: I/TAG(2582): viewgroup_dispatchTouchEvent=1
02-16 03:02:38.317: I/TAG(2582): viewgroup_onTouchEvent=1
02-16 03:02:38.317: I/TAG(2582): viewgroup_doClick

  这回button_onTouchEvent放水了,使得event继续往下“掉”,button_doClick不再执行,现在执行的是viewgroup_doClick。另外,发现button上只走了一遍ACTION_DOWN,ACTION_UP没它什么事,因为event已经不在button手中了(这么说比较形象)。

  还没完,继续,viewgroup_onTouchEvent修改为

 

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.i("TAG","viewgroup_onTouchEvent="+event.getAction());
		//return super.onTouchEvent(event);
		return false;
	}

  现在由viewgroup_onTouchEvent接着放水,点击按钮运行下结果:

02-16 03:18:56.737: I/TAG(2631): viewgroup_dispatchTouchEvent=0
02-16 03:18:56.737: I/TAG(2631): viewgroup_onInterceptTouchEvent
02-16 03:18:56.737: I/TAG(2631): button_dispatchTouchEvent=0
02-16 03:18:56.737: I/TAG(2631): button_onTouch=0
02-16 03:18:56.737: I/TAG(2631): button_onTouchEvent=0
02-16 03:18:56.737: I/TAG(2631): viewgroup_onTouchEvent=0
02-16 03:18:56.737: I/TAG(2631): Activity_onTouchEvent=0 
02-16 03:18:56.841: I/TAG(2631): Activity_onTouchEvent=1

  现在终于轮到躺地板的Activity接到event了,过程参考上面,应该也比较好理解。

  

  以下内容在stackOveflow找到,用来总结再合适不过了

 

How the Activity handles touch:

  • Activity.dispatchTouchEvent()
    • Always first to be called
    • Sends event to root view attached to Window
    • onTouchEvent()
      • Called if no views consume the event
      • Always last to be called

How the View handles touch:

  • View.dispatchTouchEvent()
    • Sends event to listener first, if exists
      • View.OnTouchListener.onTouch()
    • If not consumed, processes the touch itself
      • View.onTouchEvent()

How a ViewGroup handles touch:

  • ViewGroup.dispatchTouchEvent()
    • onInterceptTouchEvent()
      • Check if it should supersede children
      • Passes ACTION_CANCEL to active child
      • Return true once, consumes all subsequent events
    • For each child view, in reverse order they were added
      • If touch is relevant (inside view), child.dispatchTouchEvent()
      • If not handled by previous, dispatch to next view
    • If no children handle event, listener gets a chance
      • OnTouchListener.onTouch()
    • If no listener, or not handled
      • onTouchEvent()
  • Intercepted events jump over child step

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值