首页 > 系统 > Android > 正文

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

2019-11-09 17:40:47
字体:
来源:转载
供稿:网友

   关于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()详解二之小秘与领导的故事


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表