关于Android触摸事件的一些理解

   于Android的触摸事件交互,其实就是在View和ViewGroup之间的交互,view主要是指一下基础组件,比如button,TextView等,ViewGroup主要指的是LinearLayout、RelativeLayout、ListView等一些布局控件。当然事件的传递需要控件中的一些方法进行响应。

在View中的方法:

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


在ViewGroup中的方法:

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


然后关于这几种方法的返回值:

dispatchTouchEvent()方法:

1.dispatchTouchEvent()方法,这个返回值决定是否屏蔽后续事件。

false,屏蔽后续事件ACTION_MOVE,ACTION_UP。

true,不屏蔽后续事件ACTION_MOVE,ACTION_UP。

2.dispatchTouchEvent()方法,是否执行super.dispatchTouchEvent(ev)。

执行,调用onInterceptTouchEvent()方法和onTouchEvent()方法。

不执行,不调用onInterceptTouchEvent()方法和onTouchEvent()方法。

 

onInterceptTouchEvent()方法分析:

1.onInterceptTouchEvent()方法,对于这个返回值

true,拦截,不向下一层次的dispatchTouchEvent()方法传递

false,不拦截,向下一层次的dispatchTouchEvent()方法传递

这两种情况与父类的方法的是否执行都无关。

 

onTouchEvent()方法分析:

1.onTouchEvent()方法,对于这个返回值

false,屏蔽后续事件ACTION_MOVE,ACTION_UP。

true,不屏蔽后续事件ACTION_MOVE,ACTION_UP。

这两种情况与父类的方法的是否执行都无关。



首先说明一下针对dispatchTouchEvent()方法返回值为true或者false的情况,真的不知道什么时候用

下面对事件写下工程代码,首先是自定义的布局控件LayoutView1和LayoutView2,都继承了LinearLayout,需要对上面的函数进行重写,LayoutView1和LayoutView2代码相同,下面只贴出LayoutView2的

LayoutView2:

package com.lianxi.touchstudy;

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

public class LayoutView2 extends LinearLayout {
	private final String TAG = "LayoutView2";

	public LayoutView2(Context context, AttributeSet attrs) {
		super(context, attrs);
		Log.d(TAG, TAG);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, "onInterceptTouchEvent action:ACTION_DOWN");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, "onInterceptTouchEvent ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, "onInterceptTouchEvent ACTION_UP");
			break;
		case MotionEvent.ACTION_CANCEL:
			Log.d(TAG, "onInterceptTouchEvent ACTION_CANCEL");
			break;
		}
		return super.onInterceptTouchEvent(ev);
//		return false;
//		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, "onTouchEvent action:ACTION_DOWN");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, "onTouchEvent ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, "onTouchEvent ACTION_UP");
			break;
		case MotionEvent.ACTION_CANCEL:
			Log.d(TAG, "onTouchEvent ACTION_CANCEL");
			break;

		}
		return super.onTouchEvent(event);
//		return true;
//		return false;
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, "dispatchTouchEvent action:ACTION_DOWN");
			break;
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, "dispatchTouchEvent ACTION_MOVE");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(TAG, "dispatchTouchEvent ACTION_UP");
			break;
		case MotionEvent.ACTION_CANCEL:
			Log.d(TAG, "dispatchTouchEvent ACTION_CANCEL");
			break;

		}
		return super.dispatchTouchEvent(ev);
//		return true;
	}
}


TestButton:

package com.lianxi.touchstudy;

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

public class TestButton extends Button {
	private final static String tag = "TestButton";

	public TestButton(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(tag, "TestButton-onTouchEvent-ACTION_DOWN...");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(tag, "TestButton-onTouchEvent-ACTION_UP...");
			break;
		default:
			break;
		}
		return super.onTouchEvent(event);
//		return true;
//		return false;
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(tag, "TestButton-dispatchTouchEvent-ACTION_DOWN...");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(tag, "TestButton-dispatchTouchEvent-ACTION_UP...");
			break;
		default:
			break;
		}
		
		return super.dispatchTouchEvent(event);
//		return true;
	}
}


下面是布局文件activity_main.xml:

<com.lianxi.touchstudy.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.lianxi.touchstudy.LayoutView2
        android:id="@+id/linearlayout2" 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical" >

      <com.lianxi.touchstudy.TestButton
            android:id="@+id/testBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮"
            android:textColor="#0000FF"
            android:textSize="40sp" />
    </com.lianxi.touchstudy.LayoutView2>

</com.lianxi.touchstudy.LayoutView1>





最后是MainActivity.java:

package com.lianxi.touchstudy;

import android.os.Bundle;
import android.app.Activity;
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.Window;

public class MainActivity extends Activity {

	private TestButton testBtn;
	private final static String tag = "MainActivity";
	private LayoutView2 testLinelayout;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		testBtn = (TestButton) findViewById(R.id.testBtn);
		testLinelayout = (LayoutView2) findViewById(R.id.linearlayout2);  
		testBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				Log.d(tag, "testBtn---onClick...");
			}
		});
		testBtn.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View arg0, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					Log.d(tag, "testBtn-onTouch-ACTION_DOWN...");
					break;
				case MotionEvent.ACTION_UP:
					Log.d(tag, "testBtn-onTouch-ACTION_UP...");
					break;
				default:
					break;

				}
				return false;
			}
		});
		
		
        testLinelayout.setOnTouchListener(new OnTouchListener() {  
              
            @Override  
            public boolean onTouch(View v, MotionEvent event) {  
                // TODO Auto-generated method stub  
                switch(event.getAction()){  
                case MotionEvent.ACTION_DOWN:  
                    Log.d(tag, "testLinelayout-onTouch-ACTION_DOWN...");  
                    break;  
                case MotionEvent.ACTION_UP:  
                    Log.d(tag, "testLinelayout-onTouch-ACTION_UP...");  
                    break;  
                default:break;  
  
                }  
                return false;  
            }  
        });  
          
        testLinelayout.setOnClickListener(new OnClickListener() {  
              
            @Override  
            public void onClick(View v) {  
                // TODO Auto-generated method stub  
                Log.d(tag, "testLinelayout---onClick...");  
            }  
        });
	}

	public boolean dispatchTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(tag, "MainActivity-dispatchTouchEvent-ACTION_DOWN...");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(tag, "MainActivity-dispatchTouchEvent-ACTION_UP...");
			break;
		default:
			break;
		}
		return super.dispatchTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(tag, "MainActivity-onTouchEvent-ACTION_DOWN...");
			break;
		case MotionEvent.ACTION_UP:
			Log.d(tag, "MainActivity-onTouchEvent-ACTION_UP...");
			break;
		default:
			break;
		}
		return super.onTouchEvent(event);
	}

}

现在针对不同的情况进行说明:

事件发生,由MainActivity中的dispatchTouchEvent()来向下进行分发----->L1中的dispatchTouchEvent()中来向子view分发,onInterceptTouchEvent方法根据返回值来判断是否需要拦截,是否调用onTouchEvent()---->.......----->TestButton中的dispatchTouchEvent()根据返回值判断是否需要调用onTouchEvent()

首先针对TestButton

1.dispatchTouchEvent()返回值设为true,onTouchEvent()返回值为super.onTouchEvent(),点击TestButton按钮,控制台显示:




可以在打印信息中发现,onTouchEvent()没有被调用,因为只有dispatchTouchEvent()返回值为super.dispatchTouchEvent(),才会调用onTouchEvent()方法


2.1 onTouchEvent()返回值为true,dispatchTouchEvent()返回值为super.dispatchTouchEvent()




2.2 onTouchEvent()返回值为super.TouchEvent,dispatchTouchEvent()返回值为super.dispatchTouchEvent()



  

通过2.1和2.2比较可以发现,因为onTouchEvent返回值的不同,testbutton的onClick()方法被调用了。根据源码(此地不贴源码,因为太长,自己也不太懂,后面附上大神的分析帖子),发现onClick()方法是在super.onTouchEvent()中被调用的,返回值为true则说明触摸事件被testButton消耗掉了,后续的ACTION_MOVE、ACTION_UP会继续传到testButton做处理

2.3.1 此时onTouchEvent()返回值为false,dispatchTouchEvent()返回值为super.dispatchTouchEvent()



可以看出LayoutView2的onTouch()和onClick()方法被调用,testButton()没有对ACTION_UP做出反应,当textButton()的onTouchEvent()返回值为false时,说明,testButton不处理触摸事件,然后继续往上一层传,让父容器来判断是否需要处理

下面是LayoutView2分析

1.接着上部分,testButton的onTouchEvent()返回值为false,dispatchTouchEvent()的返回值为super.dispatchTouchEvent(),testButton对事件不做处理,然后LayoutView2的onTouchEvent()返回值为true,其他方法返回值仍为父类方法



此时为LayoutView2对触摸事件做出消耗,如果LayoutView2不处理,让onTouchEvent返回false,事件继续往上层走

2.1 dispatchTouchEvent()的返回值为true,其他返回父类的方法




发现每次dispatchTouchEvent()的返回值为为true的时候,onTouch()就不会调用,根据源码分析(其实是大神根据源码分析)onTouch是在super.dispatchTouchEvent()中调用的,同时如果返回值不为super.dispatchTouchEvent(),那么当前ViewGroup的onInterceptTouchEvent()和onTouchEvent()都不会调用,根据onTouchEvent和onClick()的关系,可以判断调用顺序,dispatchTouchEvent(返回值为super.dispatchTouchEvent())--->onInterceptTouchEvent()--->onTouch()--->onTouchEvent(返回值为super.onTouchEvent())--->onClick()

2.2 dispatchTouchEvent()的返回值为super.dispatchTouchEvent(),onInterceptTouchEvent()返回true进行拦截,其他返回其父类方法




可以发现,onTouchEvent()没有对事件做处理,调用了onClick()方法

2.3 dispatchTouchEvent()的返回值为super.dispatchTouchEvent(),onInterceptTouchEvent()返回true进行拦截,onTouchEvent()返回true,事件由layoutView2来处理消耗,其他返回其父类方法




事件被消耗,如果layoutView2不想处理,onTouchEvent()返回false,事件继续往上走


总结:现在依然不知道dispatchTouchEvent()返回true或者false的作用,大致流程就是以上所写,如果onTouchEvent()不对事件做处理,其控件所绑定的onClick()就会执行,onTouch()只要dispatchTouchEvent()返回super.dispatchTouchEvent(),就会执行。


上边关于源码的分析,详见大神的帖子:

Android事件传递机制

android事件传递机制以及onInterceptTouchEvent()和onTouchEvent()详解二之小秘与领导的故事









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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值