以ontouch为例说明android事件发送机制

来源:互联网 发布:太极拳实战 知乎 编辑:程序博客网 时间:2024/05/20 06:04

android里面和touch相关的方法最常见的有四个:onTouch,dispatchTouchEvent,onTouchEvent,如果是一个GroupView的话还有一个onInterceptTouchEvent。

这四个方法有什么关系?很多新手搞不明白,我在网上找了很多的资料,发现自己的研究结果与资料上的有出入。所以将自己的结论写出来,Android的事件传递机制到底是怎么样的,也可以由此一探究竟。

我这例子实在网上的例子改造的,原来文章的链接:http://www.blogjava.net/lzqdiy/archive/2011/05/08/349794.html

先贴出我的代码,在做仔细的分析

复制代码
<?xml version="1.0" encoding="utf-8"?><view android:layout_width="fill_parent"      android:layout_height="fill_parent"      class="com.example.AndroidTouchTest.MyLinearLayout"      xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/view">    <com.example.AndroidTouchTest.MyTextView            android:layout_width="200px"            android:layout_height="200px"            android:id="@+id/tv"            android:text="lzqdiy"            android:textSize="40sp"            android:textStyle="bold"            android:background="#FFFFFF"            android:textColor="#0000FF"/></view>
复制代码
复制代码
package com.example.AndroidTouchTest;import android.app.Activity;import android.os.Bundle;public class MyActivity extends Activity {    /**     * Called when the activity is first created.     */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);    }}
复制代码
View Code
View Code
View Code

 这里的代码编辑器不太好用,想看代码的可以到这里:http://www.cnblogs.com/HighFun/archive/2013/03/26/2979901.html

点击textiew的时候,会看到下面的打印:

03-23 17:22:23.545: DEBUG/MyLinearLayout(2459): dispatchTouchEvent action:ACTION_DOWN
03-23 17:22:23.545: DEBUG/MyLinearLayout(2459): onInterceptTouchEvent action:ACTION_DOWN
03-23 17:22:23.545: DEBUG/MyLinearLayout(2459): onInterceptTouchEvent action: flag false
03-23 17:22:23.545: DEBUG/MyTextView(2459): dispatchTouchEvent action:ACTION_DOWN
03-23 17:22:23.545: DEBUG/MyTextView(2459): onTouch action:ACTION_DOWN
03-23 17:22:23.545: DEBUG/MyTextView(2459): onTouch action: FORCE SET flag false
03-23 17:22:23.545: DEBUG/MyTextView(2459): ---onTouchEvent action:ACTION_DOWN
03-23 17:22:23.545: DEBUG/MyTextView(2459): ---onTouchEvent action: flag false
03-23 17:22:23.545: DEBUG/MyTextView(2459): onTouchEvent action: flag false
03-23 17:22:23.545: DEBUG/MyLinearLayout(2459): onTouch action:ACTION_DOWN
03-23 17:22:23.545: DEBUG/MyLinearLayout(2459): onTouch action: FORCE SET flag false
03-23 17:22:23.545: DEBUG/MyLinearLayout(2459): ---onTouchEvent action:ACTION_DOWN
03-23 17:22:23.554: DEBUG/MyLinearLayout(2459): ---onTouchEvent action: flag false
03-23 17:22:23.554: DEBUG/MyLinearLayout(2459): dispatchTouchEvent action: flag false

调用顺序整理如下:颜色表示控件,缩进表示调用关系。

MyLinearLayout(2459): dispatchTouchEvent

  MyLinearLayout(2459): onInterceptTouchEvent

  MyTextView(2459): dispatchTouchEvent action

    MyTextView(2459): onTouch

    MyTextView(2459): ---onTouchEvent

  MyLinearLayout(2459): onTouch

  MyLinearLayout(2459): ---onTouchEvent

MyLinearLayout(2459): dispatchTouchEven

 

这个是什么意思呢?

首先我们要分析下这几个函数的作用和返回值的意义

dispatchTouchEvent是用来分发事件的,控件的事件的分发都是通过这个函数来完成的。

onInterceptTouchEvent是判断是否截取事件,为什么要截取事件呢?因为控件重要有可能包含其他的控件,比如说,本例子代码中linearlayout中包含了一个textiew。他的作用就是决定这个事件是否需要传递給子控件。不过注意仅仅是GroupView的控件才有哦,有些控件,像textview就没法办法包含子控件的,所以它就没有这个方法。

ontouch是事件监听器的方法,只要有触摸的操作就是有这个方法。

onTouchEvent是触摸事件发生以后产生的处理。

他们都有一个boolean的返回值,false表示该事件需要继续传播,true表示该事件不用继续传播了。

每点击一次屏幕会有三个事件发生:ACTION_DOWN, ACTION_MOVE, ACTION_UP。 这里可以看到如果dispatchTouchEvent返回值是false的话,则不会再有后续的事件,后续的事件被丢弃掉了。

LinearLayout的调用函数图

 

LinearLayout的 dispatchTouchEvent代码

View Code

Textiew的调用流程

复制代码
 1     public boolean dispatchTouchEvent(MotionEvent event) { 2         if (mInputEventConsistencyVerifier != null) { 3             mInputEventConsistencyVerifier.onTouchEvent(event, 0); 4         } 5  6         if (onFilterTouchEventForSecurity(event)) { 7             //noinspection SimplifiableIfStatement 8             ListenerInfo li = mListenerInfo; 9             if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED10                     && li.mOnTouchListener.onTouch(this, event)) {11                 return true;12             }13 14             if (onTouchEvent(event)) {15                 return true;16             }17         }18 19         if (mInputEventConsistencyVerifier != null) {20             mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);21         }22         return false;23     }
复制代码

可以看到TextView的dispatchTouchEvent先调用的Ontouch(9,10行)如果调用结果返回true则返回,如果是false则继续调用Ontouchevent。

正式基于这两种传输机制,事件得以在控件中不断传输。

那么事件是怎么通过父控件传入到子控件呢?

复制代码
 1                 while (target != null) { 2                     final TouchTarget next = target.next; 3                     if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { 4                         handled = true; 5                     } else { 6                         final boolean cancelChild = resetCancelNextUpFlag(target.child) 7                         || intercepted; 8                         if (dispatchTransformedTouchEvent(ev, cancelChild, 9                                 target.child, target.pointerIdBits)) {10                             handled = true;
复制代码

这是在LinearLayout中的代码段,可以看到调用了dispatchTransformedTouchEvent方法,代码比较长,只给出一部分。

复制代码
    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,            View child, int desiredPointerIdBits) {        final boolean handled;        // Canceling motions is a special case.  We don't need to perform any transformations        // or filtering.  The important part is the action, not the contents.        final int oldAction = event.getAction();        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {            event.setAction(MotionEvent.ACTION_CANCEL);            if (child == null) {                handled = super.dispatchTouchEvent(event);            } else {                handled = child.dispatchTouchEvent(event);            }            event.setAction(oldAction);            return handled;        }…………
复制代码

可以看到会寻找子控件,并且调用子控件的dispatchTouchEvent,如果没有就调用父类(不是父控件)的dispatchTouchEvent。而ViewGroup的父类就是View。

机制就是这样,不同的返回值会有不同的调用顺序,但是原理都是一样的。可以修改没有方法的返回值来查看代码的调用情况。

源代码地址:https://github.com/Dothegod/AndroidTouchTest/

原创粉丝点击