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

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) == ENABLED
10                     && 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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值