您的位置:首页 > 移动开发 > Android开发

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

2017-02-06 15:39 288 查看
   关于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()详解二之小秘与领导的故事


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: