理解Android中的TouchEvent事件分发机制

1、首先我们自定义一个LinearLayout和Button,然后在里面复写dispatchTouchEvent、onInterceptTouchEvent(Button没有这个函数)、onTouchEvent这三个函数。

其中dispatchTouchEvent函数是用来分发事件的,onInterceptTouchEvent事件是用来判断是否拦截事件的,onTouchEvent则用来处理具体事物。

package com.tang.Javen;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;

public class TouchEventLinearLayout extends LinearLayout
{

	public TouchEventLinearLayout(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventLinearLayout dispatchTouchEvent");
		return super.dispatchTouchEvent(ev);
	}
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventLinearLayout onInterceptTouchEvent");
		return super.onInterceptTouchEvent(ev);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventLinearLayout onTouchEvent");
		return super.onTouchEvent(event);
	}
}

package com.tang.Javen;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;

public class TouchEventButton extends Button
{

	public TouchEventButton(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventButton dispatchTouchEvent");
		return super.dispatchTouchEvent(event);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventButton onTouchEvent");
		return super.onTouchEvent(event);
	}
}

2、然后在Activity中复写dispatchTouchEvent、onTouchEvent,查看log

<?xml version="1.0" encoding="utf-8"?>
<com.tang.Javen.TouchEventLinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

	<com.tang.Javen.TouchEventButton 
	    android:id="@+id/btu1"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="button_01"/>
	
</com.tang.Javen.TouchEventLinearLayout>

package com.tang.Javen;

import android.app.Activity;

public class ViewGroupTouchEventActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
    	// TODO Auto-generated method stub
    	System.out.println("ViewGroupTouchEventActivity dispatchTouchEvent");
    	return super.dispatchTouchEvent(ev);
    }
    
    
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
    	// TODO Auto-generated method stub
    	System.out.println("ViewGroupTouchEventActivity onTouchEvent");
    	return super.onTouchEvent(event);
    }
}
运行起来


点击Activity,查看打印


从打印中可以看出onTouchEvent事件是从Activity的dispatchTouchEvent函数传入到LinearLayout的dispatchTouchEvent中去的。

然后我们来分析各个函数的返回值对事件传递的影响:

1、把ViewGroupTouchEventActivity中的dispatchTouchEvent返回值改为true或者false,查看打印。

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
    	// TODO Auto-generated method stub
    	System.out.println("ViewGroupTouchEventActivity dispatchTouchEvent");
    	//return super.dispatchTouchEvent(ev);
    	return true;
    }


这里可以看到当dispatchTouchEvent返回true或者false时,则这TouchEvent事件就不会传递下去了,这里打印两次是一个DOWN事件和一个UP事件。只有return super.dispatchTouchEvent(ev)时事件才会被分发下去。

然后这个事件就会传递到ViewGroup的dispatchTouchEvent中继续分发。

2、当把TouchEventLinearLayout中的dispatchTouchEvent返回为true时,DOWN和UP事件不会继续分发下去,既不向上也不向下传递。

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventLinearLayout dispatchTouchEvent");
//		return super.dispatchTouchEvent(ev);
		return true;
	}

3、把TouchEventLinearLayout中的dispatchTouchEvent返回改为false时

@Override
	public boolean dispatchTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventLinearLayout dispatchTouchEvent");
//		return super.dispatchTouchEvent(ev);
//		return true;
		return false;
	}

查看打印可以知道,当TouchEventLinearLayout中的dispatchTouchEvent返回为false时,DOWN事件则不会再向下传递了,而是直接返回到上层Activiy中去,而UP事件则不经过TouchEventLinearLayout,而是直接在Activity中接收了。


4、当TouchEventLinearLayout中的dispatchTouchEvent的返回值为super.dispatchTouchEvent时,则会询问该ViewGroup中的onInterceptTouchEvetn,如果onInterceptTouchEvent返回true时,则说明该ViewGroup拦截此次TouchEvent,交给该ViewGroup的onTouchEvent进行处理,如果返回false的话,则说明不会拦截此次的TouchEvent,并且继续向下传递,询问下一层ViewGroup的dispatchTouchEvent。

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventLinearLayout dispatchTouchEvent");
		return super.dispatchTouchEvent(ev);
//		return true;
//		return false;
	}
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventLinearLayout onInterceptTouchEvent");
//		return super.onInterceptTouchEvent(ev);
		return true;
//		return false;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		// TODO Auto-generated method stub
		switch (event.getAction())
		{
		case MotionEvent.ACTION_DOWN:
			System.out.println("TouchEventLinearLayout onTouchEvent ACTION_DOWN");
			break;
		case MotionEvent.ACTION_MOVE:
			System.out.println("TouchEventLinearLayout onTouchEvent ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("TouchEventLinearLayout onTouchEvent ACTION_UP");
			break;
		default:
			break;
		}
//		return super.onTouchEvent(event);
		return true;
//		return false;
	}
当该ViewGroup的onTouchEvent返回为true时,则DOWN、MOVE、UP事件就都在该ViewGroup中的onTouchEvent事件中接收

当该ViewGroup的onTouchEvent返回为false或者super.onTouchEvent(event)时,则DOWN事件会在该ViewGroup中接收,然后向上传递上去,然后之后的MOVE、UP事件则不经过该ViewGroup,直接在上层Activity接收


5、当在ViewGroup中的dispatchTouchEvent的返回值为super.dispatchTouchEvent,且该ViewGroup的onInterceptTouchEvent返回false或者super.onInterceptTouchEvent时,则事件继续向下传递,然后当TouchEventButton中的dispatchTouchEvent返回true时。

	@Override
	public boolean dispatchTouchEvent(MotionEvent event)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventButton dispatchTouchEvent");
//		return super.dispatchTouchEvent(event);
		return true;
	}

当事件分发到View是,如果view的dispatchTouchEvent返回的是true,则事件不再分发。


当view的dispatchTouchEvent返回为false时,则DOWN事件向上传递到上层的onTouchEvent事件中去,如果上层onTouchEvent事件返回false或者super.onTouchEvent,则继续向上传递,而MOVE、UP则直接在最终接收事件层中接收,否则所有事件都在上层的onTouchEvent中接收。


当view的dispatchTouchEvent返回为super.dispatchTouchEvent时,则事件传递到该View的onTouchEvent事件中去,如果该View中的onTouchEvent返回true或者super.onTouchEvent,则DOWN、MOVE、UP事件全部在该View的onTouchEvent事件中接收了。


当View中的onTouchEvent返回false时,则该View中接收DOWN事件后,会继续向上传递,然后查看上层的onTouchEvent的返回值,以此类推,MOVE、UP事件则直接在上层接收不经过该View


6、添加一个TouchEventRelativeLayout继承RelativeLayout

package com.tang.Javen;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;

public class TouchEventRelativeLayout extends RelativeLayout
{

	public TouchEventRelativeLayout(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventRelativeLayout dispatchTouchEvent");
//		return super.dispatchTouchEvent(ev);
		return false;
	}
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev)
	{
		// TODO Auto-generated method stub
		System.out.println("TouchEventRelativeLayout onInterceptTouchEvent");
		return super.onInterceptTouchEvent(ev);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		// TODO Auto-generated method stub
		switch (event.getAction())
		{
		case MotionEvent.ACTION_DOWN:
			System.out.println("TouchEventRelativeLayout onTouchEvent ACTION_DOWN");
			break;
		case MotionEvent.ACTION_MOVE:
			System.out.println("TouchEventRelativeLayout onTouchEvent ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			System.out.println("TouchEventButton onTouchEvent ACTION_UP");
			break;
		default:
			break;
		}
		return super.onTouchEvent(event);
	}
	
}

<?xml version="1.0" encoding="utf-8"?>
<com.tang.Javen.TouchEventLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <com.tang.Javen.TouchEventRelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <com.tang.Javen.TouchEventButton
            android:id="@+id/btu1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="button_01" />
    </com.tang.Javen.TouchEventRelativeLayout>

</com.tang.Javen.TouchEventLinearLayout>

当事件分发到这个RelativeLayout的dispatchTouchEvent时,当该dispatchTouchEvent返回false时,向上传递,然后它是判断上层的onTouchEvent的返回值来决定事件在哪里接收。



总结:

1、当dispatchTouchEvent返回true时,则停止分发;当dispatchTouchEvent返回false时,则向上传递,然后根据上层的onTouchEvent事件的返回值决定事件在哪接收;当dispatchTouchEvent返回super.dispatchTouchEvent时,则继续传递。

      如果该层是ViewGroup,则判断该层的onInterceptTouchEvent,如果onInterceptTouchEvent返回true,则事件直接在该层的onTouchEvent中接收,如果返回false或者super.onInterceptTouchEvent则继续向下传递,以此类推。

     如果该层是View,则直接在该层的onTouchEvent中判断返回值进行接收。

2、在onTouchEvent事件中,如果返回true,则所有的事件在该onTouchEvent接收;如果返回false则会继续向上传递,然后判断上层的onTouchEvent的返回值,以此类推。

3、DOWN事件会随着事件分发在走,当确定了具体在哪个onTouchEvent事件中接收后,MOVE和UP事件就直接到该onTouchEvent事件中去接收了。

4、onTouchEvent的返回值中,ViewGroup的返回值为false和super.onTouchEvent效果一样;View中的返回值为true和super.onTouchEvent效果一样。

 

流程图下载:http://download.csdn.net/detail/hedaogelaoshu/7933063

代码下载:http://download.csdn.net/detail/hedaogelaoshu/7933081


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值