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的若是是空白區域,則就會兩個都被調用,形成重複調用的問題。

相關文章
相關標籤/搜索