android touch event事件的传递顺序。

最近在研究android的事件传递流程,在网上也发现了一些文章,但有的看起来不是很明白。先看看这几个事件的定义html

public boolean dispatchTouchEvent (MotionEvent ev)

Since:   API Level 1

Pass the touch screen motion event down to the target view, or this view if it is the target.android

public boolean onInterceptHoverEvent (MotionEvent event)

Since:   API Level 14

Implement this method to intercept hover events before they are handled by child views.web

This method is called before dispatching a hover event to a child of the view group or to the view group's own onHoverEvent(MotionEvent) to allow the view group a chance to intercept the hover event. This method can also be used to watch all pointer motions that occur within the bounds of the view group even when the pointer is hovering over a child of the view group rather than over the view group itself.api

 

public boolean onTouchEvent (MotionEvent event)

Since:   API Level 1

Implement this method to handle touch screen motion events.app

 

onInterceptTouchEvent:ide

onInterceptTouchEvent是在ViewGroup里面定义的。Android中的layout布局类通常都是继承此类的。onInterceptTouchEvent是用于拦截手势事件的,每一个手势事件都会先调用onInterceptTouchEvent。布局

onTouchEvent:ui

onTouchEvent一样也是在view中定义的一个方法。处理传递到view 的手势事件。手势事件类型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL等事件this

当一次点击事件发生的时候,首先是底层的activity收到dispatchTouchEvent ,而后传递给最底层的layout ,触发该layout的dispatchTouchEvent,而后调用该layout的onInterceptTouchEvent,而后传递给该布局上的控件,并触发控件的dispatchTouchEvent,而后触发onTouchEvent。spa

 

TouchDemoActivity
package com.example.touchdemo;


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

public class TouchDemoActivity extends Activity {
    public static final String TAG = "TouchDemoActivity";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        Log.d("TouchDemoActivity", "onTouchEvent getAction:"+event.getAction());
        return super.onTouchEvent(event);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("TouchDemoActivity", "dispatchTouchEvent getAction:"+ev.getAction());
        return super.dispatchTouchEvent(ev);
    }
    @Override
    public boolean dispatchTrackballEvent(MotionEvent ev) {
        Log.d("TouchDemoActivity", "dispatchTrackballEvent getAction:"+ev.getAction());
        return super.dispatchTrackballEvent(ev);
    }
    
    
}
MyView
package com.example.touchdemo;


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

public class MyView extends Button {
    public static final String TAG = "MyView";
    public MyView(Context context){
        super(context);
    }
    
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "onTouchEvent. getAction:"+event.getAction());
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e(TAG, "dispatchTouchEvent. getAction:"+event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean dispatchTrackballEvent(MotionEvent event) {
        Log.e(TAG, "dispatchTrackballEvent. getAction:"+event.getAction());
        return super.dispatchTrackballEvent(event);
    }
    
    

}
<?xml version="1.0" encoding="utf-8"?>
<com.example.touchdemo.MyLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
     >

    <com.example.touchdemo.MyView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</com.example.touchdemo.MyLayout>
布局文件

 

 

运行结果: 

04-03 19:07:30.805: D/TouchDemoActivity(8860): dispatchTouchEvent getAction:0
04-03 19:07:30.805: E/MyLayout(8860): dispatchTouchEvent. getAction:0
04-03 19:07:30.805: E/MyLayout(8860): onInterceptTouchEvent getAction:0
04-03 19:07:30.805: E/MyView(8860): dispatchTouchEvent. getAction:0
04-03 19:07:30.806: E/MyView(8860): onTouchEvent. getAction:0

这个是没有任何拦截的时候,事件是从底层逐步派发过去的,响应事件也是从上层逐步响应回来。

试着修改一下代码看看,咱们先把MyView的onTouchEvent给返回false,说明该控件没有处理该事件,看看是什么效果。

04-03 19:46:30.520 D/TouchDemoActivity(12404): dispatchTouchEvent getAction:0
04-03 19:46:30.520 E/MyLayout(12404): dispatchTouchEvent. getAction:0
04-03 19:46:30.521 E/MyLayout(12404): onInterceptTouchEvent getAction:0
04-03 19:46:30.521 E/MyView  (12404): dispatchTouchEvent. getAction:0
04-03 19:46:30.521 E/MyView  (12404): onTouchEvent. getAction:0
04-03 19:46:30.521 E/MyLayout(12404): onTouchEvent getAction:0

从上面的运行效果能够看出,onTouchEvent回到了其上一级目录的onTouchEvent里面,也就是说,若是最上层的view不处理onTouchEvent,则会返回到上一级的onTouchEvent。

下面来看看viewgroup的onInterceptTouchEvent事件,若是该事件给返回了true,看有什么效果。

04-03 19:50:24.505 D/TouchDemoActivity(12940): dispatchTouchEvent getAction:0
04-03 19:50:24.505 E/MyLayout(12940): dispatchTouchEvent. getAction:0
04-03 19:50:24.506 E/MyLayout(12940): onInterceptTouchEvent getAction:0
04-03 19:50:24.506 E/MyLayout(12940): onTouchEvent getAction:0

从上面能够看出,只要处理了onInterceptTouchEvent,也不会继续往下传输了,而会调用当前viewgroup的ontouchevnent.

因此当你点击的layout的空白处的时候,事件也就到了当前的layout为止了,不会继续往下执行,这个时候就会调用当前layout的ontouchevnent。

今天就遇到一个问题,添加的滑动事件,在ontouchevnent和onInterceptTouchEvent都添加了,结果有时候会触发两次滑动事件,开始很奇怪为啥仍是几率性出现的,后来才知道,若是touch的不是空白区域,则当前layout的ontouchevnent不会被触发,因此没有问题,而touch的若是是空白区域,则就会两个都被调用,形成重复调用的问题。

相关文章
相关标签/搜索