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

Android的Touch事件分发机制,看完这个就够了

2015-08-03 17:11 615 查看
最近在整理 关于Android的Touch事件的分发机制,首先Touch事件的方法包括三种:dispatchTouchEvent(MotionEvent event) , onInterceptTouchEvent(MotionEvent ev) , onTouchEvent(MotionEvent event) ,下面是这三个方法在界面中的调用映射表:

Touch事件的方法方法介绍ViewViewGroupActivity
dispatchTouchEvent事件的分发yesyesyes
onInterceptTouchEvent事件的拦截yesyesno
onTouchEvent事件的响应yesyesyes
Ps:这里的View 若只是Button或者其他不包含子控件的View是不包含OnInterceptTouchEvent方法的。

下面进行事件分发的详细解析:

Touch事件的方法\返回值解析truefalsesuper()
dispatchTouchEvent每次的Touch都会由Activity的dispatchTouchEvent向下层的View或ViewGroup进行事件分发☞当前的控件自己处理事件1、若该View是Activity或者是button等不含子控件的View,则将事件分发给自己处理 ☞ ; 2、否则传递给上层的Activity或者父控件的OnTouchEvent方法 ☝☟ 下发给Activity的子控件或View自身的OnIntercepterTouchEvent
onInterceptTouchEvent是否拦截事件☞ 当前View的OnTouchEvent☟ 子控件的dispatch
onTouchEvent事件的响应☞ 当前View☝ 父控件的TouchEvent

解释:

☝ : 表示向上父类传递事件

☟ : 表示向下子类分发事件

☞ : 表示由自己来处理事件

下面 我们通过代码来验证一下我们上面的理论:

首先定义两个子布局:

tauchButton:

public class tauchButton extends LinearLayout {
public tauchButton(Context context) {
super(context);
}

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

public tauchButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("zgy", "TouchEventChilds | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
return super.onTouchEvent(event);
}

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i("zgy", "TouchEventChilds | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
return super.dispatchTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i("zgy", "TouchEventChilds | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.onInterceptTouchEvent(ev);
}

}


父控件touchLinearlayout:

public class touchLinearlayout extends LinearLayout {
public touchLinearlayout(Context context) {
super(context);
}

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

public touchLinearlayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("zgy", "TouchEventFather | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
return super.onTouchEvent(event);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("zgy", "TouchEventFather | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.dispatchTouchEvent(ev);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("zgy", "TouchEventFather | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.onInterceptTouchEvent(ev);
}

}


activity的layout布局:

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

<com.example.lk.helloworld.view.touchLinearlayout
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="@color/bg_discount"
android:layout_gravity="center">

<com.example.lk.helloworld.view.tauchButton
android:id="@+id/buttonChild"
android:layout_width="200dp"
android:layout_height="200dp"
android:text="button"
android:background="@color/bg_blue_light"
android:layout_gravity="center"
android:layout_marginLeft="20dp"
/>
</com.example.lk.helloworld.view.touchLinearlayout>

</LinearLayout>


Activity1:

package com.example.lk.helloworld;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;

import com.example.lk.helloworld.utils.TouchEventUtil;

/**
*
*/
public class Activity1 extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1_layout);

}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.w("zgy", "TouchEventActivity | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
return super.onTouchEvent(event);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.w("zgy", "TouchEventActivity | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.dispatchTouchEvent(ev);
}
}


首先我们先看看都使用super的方法时是神马结果;

case1 : 所有的返回值都调用super方法



这里我们可以看出,首先由Activity的dispatchTouchEvent方法,想下分发事件,由于是Activity,没有OnIterceptTouchEvent因此是分发给子控件的dispatchTouchEvent方法,当到TouchEventFather分发事件的时候,就是分发给了自己的OnIntercepterTouchEvent ; 这时候调用的依然是super的方法,根据上面的表格显示,默认不拦截,就把事件分发给了下一个控件的dispatchTouchEvent , 最终由于都没有消耗该事件,于是事件会由子控件返回给当前的Acticity,然后释放掉。

下面我们随机测试一下其他的情况:

case2 : 父控件的onTouchEvent的返回值设置为true



截图可以看出,当运行到TouchEventFather的OnTouchEvent的时候,就把事件给消耗掉了,就不会走Activity的OntouchEvent的方法了;

case3:tauchButton的dispatchTouchEvent的返回值是false



截图可以发现,当运行到tauchButton的dispatchEvent方法,返回false时,事件不再向下分发,而是将事件传递给上层的View的OntouchEvent方法;

剩下的 都经过实践的出,这里不再一一列举。

当然到这里,我们基本搞懂了View的事件分发,不过我们似乎还忘了一点事情,那就是View的监听事件:setOnTouchListener 和 setOnClickListener.到这里的时候 我突然想到如果给button加一个监听事件会怎么样。

下面将Activity该成如下形式:

package com.example.lk.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.example.lk.helloworld.utils.TouchEventUtil;
import com.example.lk.helloworld.view.tauchButton;

/**
*
*/
public class Activity1 extends Activity {

private tauchButton buttonChild;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1_layout);

buttonChild = (tauchButton)findViewById(R.id.buttonChild);
buttonChild.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("Activity1.this","touchListener 事件触发");
return true;
}
});
buttonChild.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("Activity1.this", "clickListener 事件触发");
}
});
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.w("zgy", "TouchEventActivity | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
return super.onTouchEvent(event);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.w("zgy", "TouchEventActivity | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
return super.dispatchTouchEvent(ev);
}
}




我们再次运行会发现如图所示。当事件分发到TouchEventChilds的OntouchEvent的时候,被touchListener事件拦截,并且消耗掉事件。

如果我们把setOnTouchListener的返回值设置为false;



这时我们可以发现,事件会被一直传递下去,直到传递给setOnClickListener事件。如果没有监听Onclick事件的时候:



事件会按原路返回到Activity然后释放掉;

那么我们现在可以发现:

触摸事件传递顺序:dispatchTouchEvent–>>onTouch–>>onTouchEvent–>>onClick。而且是当OnTouchEvent的手势ACTION_UP结束的时候才会调用Onclick方法。到这里我们基本对Touch的事件有了一定的了解了。

Ps:本文主要参考下面的blog:[ /article/4917556.html ]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: