文档章节

Android 编程下 Touch 事件的分发和消费机制

wisely
 wisely
发布于 2014/04/22 17:20
字数 1340
阅读 13
收藏 0
点赞 0
评论 0

Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev)onInterceptTouchEvent(MotionEvent ev)onTouchEvent(MotionEvent ev);能够响应这些方法的控件包括:ViewGroupViewActivity。方法与控件的对应关系如下表所示:

Touch 事件相关方法 方法功能  ViewGroup View   Activity    
public boolean dispatchTouchEvent(MotionEvent ev) 事件分发  Yes Yes Yes
public boolean onInterceptTouchEvent(MotionEvent ev) 事件拦截 Yes Yes no
public boolean onTouchEvent(MotionEvent ev) 事件响应 Yes Yes Yes

从这张表中我们可以看到 ViewGroup 和 View 对与 Touch 事件相关的三个方法均能响应,而 Activity 对 onInterceptTouchEvent(MotionEvent ev) 也就是事件拦截不进行响应。另外需要注意的是 View 对 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev) 的响应的前提是可以向该 View 中添加子 View,如果当前的 View 已经是一个最小的单元 View(比如 TextView),那么就无法向这个最小 View 中添加子 View,也就无法向子 View 进行事件的分发和拦截,所以它没有 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev),只有 onTouchEvent(MotionEvent ev)。

一、Touch 事件分析

▐ 事件分发:public boolean dispatchTouchEvent(MotionEvent ev)

Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:

  • 如果 return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时事件会停止向下传递;

  • 如果 return false,事件分发分为两种情况:

  1. 如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费;

  2. 如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的  onTouchEvent 进行消费。

  • 如果返回系统默认的 super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。


事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev) 

外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:

  • 如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理;

  • 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;

  • 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),事件默认会被拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理。

▐ 事件响应:public boolean onTouchEvent(MotionEvent ev)

在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:

  • 如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。

  • 如果返回了 true 则会接收并消费该事件。

  • 如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。

到这里,与 Touch 事件相关的三个方法就分析完毕了。下面的内容会通过各种不同的的测试案例来验证上文中三个方法对事件的处理逻辑。

二、Touch 案例介绍

同样在开始进行案例分析之前,我需要说明测试案例的结构,因为所有的测试都是针对这一个案例来进行的,测试中只是通过修改每个控件中与 Touch 事件相关的三个方法的返回值来体现不同的情况。先来看张图:

<?xml version="1.0" encoding="utf-8"?>
<cn.sunzn.tevent.TouchEventFather xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#468AD7"
    android:gravity="center"
    android:orientation="vertical" >

    <cn.sunzn.tevent.TouchEventChilds
        android:id="@+id/childs"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:background="#E1110D"
        android:text="@string/hello" />

</cn.sunzn.tevent.TouchEventFather>

package cn.sunzn.tevent;

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

public class TouchEventFather extends LinearLayout {

    public TouchEventFather(Context context) {
        super(context);
    }

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

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

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

    public boolean onTouchEvent(MotionEvent ev) {
        Log.d("sunzn", "TouchEventFather | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
        return super.onTouchEvent(ev);
    }

}

package cn.sunzn.tevent;

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

public class TouchEventChilds extends LinearLayout {

    public TouchEventChilds(Context context) {
        super(context);
    }

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

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

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

    public boolean onTouchEvent(MotionEvent ev) {
        Log.d("sunzn", "TouchEventChilds | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
        return super.onTouchEvent(ev);
    }

}

package cn.sunzn.tevent;

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

public class TouchEventActivity extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

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

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

}

package cn.sunzn.tevent;

import android.view.MotionEvent;

public class TouchEventUtil {
    
    public static String getTouchAction(int actionId) {
        String actionName = "Unknow:id=" + actionId;
        switch (actionId) {
        case MotionEvent.ACTION_DOWN:
            actionName = "ACTION_DOWN";
            break;
        case MotionEvent.ACTION_MOVE:
            actionName = "ACTION_MOVE";
            break;
        case MotionEvent.ACTION_UP:
            actionName = "ACTION_UP";
            break;
        case MotionEvent.ACTION_CANCEL:
            actionName = "ACTION_CANCEL";
            break;
        case MotionEvent.ACTION_OUTSIDE:
            actionName = "ACTION_OUTSIDE";
            break;
        }
        return actionName;
    }
    
}

如上是原博客的代码,

下面的地址是我用ViewGroup实现的比较复杂一点的例子程序:

例子程序


本文转载自:http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html

共有 人打赏支持
wisely

wisely

粉丝 32
博文 30
码字总数 9217
作品 0
杭州
程序员
安卓自定义View进阶-事件分发机制原理

安卓自定义View进阶-事件分发机制原理 之前讲解了很多与View绘图相关的知识,你可以在 安卓自定义View教程目录 中查看到这些文章,如果你理解了这些文章,那么至少2D绘图部分不是难题了,大部...

猴亮屏 ⋅ 05/22 ⋅ 0

Android6.0触摸事件分发机制解读

本篇博文是Android触摸事件分发机制系列博文的第一篇,带领大家从全局掌握Android触摸事件分发机制。特别声明的是,本源码解读是基于最新的Android6.0版本。 (一)Android6.0源码解读之Vie...

mynameishuangshuai ⋅ 2016/10/24 ⋅ 0

第六章 Android 开发中的View和事件分发机制

1. 概述   作为Android开发中最常见的一个控件,个人觉得有必要谈谈了。我们刚开始接触Android的时候最常见的一些基本控件就有TextView,EditText,Button......,但是细心的你会发现它们的父...

忆念成风 ⋅ 2017/11/09 ⋅ 0

android事件分发机制总结

Android事件分发机制 在android 普通view(不包含ViewGroup)和activity中主要有一下两个方法处理事件: public boolean dispatchTouchEvent(MotionEvent ev) // 分发事件public boolean on...

亓斌哥哥 ⋅ 2014/10/08 ⋅ 1

一步步探索学习Android Touch事件分发传递机制(三)

前言 该系列文章分三篇: 一步步探索学习Android Touch事件分发传递机制(一) 通过写demo打Log,以ACTIONDOWN事件为例,完整了解整个Android Touch事件分发传递机制。 一步步探索学习Andro...

单人旅途alan ⋅ 2017/12/04 ⋅ 0

《android的事件分发机制》

先看代码 View inflate = LayoutInflater.from(this).inflate(R.layout.xxx, null); EditText viewById = (EditText) inflate.findViewById(R.id.edit_content); viewById.setOnTouchListene......

吕檀溪 ⋅ 2016/05/09 ⋅ 2

【Android】打造下拉放大效果

前言 在其他App上看到了这样的一个效果,感觉有点意思,于是决定实现一个类似的效果。 (其实是iOS的同学在是现功能的时候秀了一波操作) 效果大概是这样子的: UI看完后 “这个效果不错啊”...

带心情去旅行 ⋅ 06/19 ⋅ 0

Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制

ViewGroup的事件分发机制 我们用手指去触摸Android手机屏幕,就会产生一个触摸事件,但是这个触摸事件在底层是怎么分发的呢?这个我还真不知道,这里涉及到操作硬件(手机屏幕)方面的知识,...

董家二少 ⋅ 2014/04/04 ⋅ 1

10分钟了解Android的事件分发

什么是事件分发? 大家知道Android中的视图是由一个个View嵌套构成的层级视图,即一个View里包含有子View,而这个子View里面又可以再添加View。当用户触摸屏幕产生一系列事件时,事件会由高到...

codeGoogle ⋅ 05/21 ⋅ 0

Android6.0源码解读之Activity点击事件分发机制

本篇博文是Android点击事件分发机制系列博文的第四篇,主要是从解读Activity类的源码入手,根据源码理清Activity点击事件分发原理,并掌握Activity点击事件分法机制。特别声明的是,本源码解...

mynameishuangshuai ⋅ 2016/10/23 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring Cloud构建微服务架构—创建“服务注册中心”

创建一个基础的Spring Boot工程,命名为eureka-server,并在pom.xml中引入需要的依赖内容: <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-par......

itcloud ⋅ 11分钟前 ⋅ 0

拖动

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>event</title> <style> #box { width: 100px; height: 100px; background-color: aquamarine; position: absolute; } </style......

fyliujj ⋅ 14分钟前 ⋅ 0

es6 polyfill array

polyfill之javascript函数的兼容写法——Array篇 1. Array.isArray(obj) if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[objec......

球球 ⋅ 16分钟前 ⋅ 0

kibana启动异常

检查一下:kibana.yml 每一对key:value中,冒号之后应有空格。

增删改查1 ⋅ 18分钟前 ⋅ 0

js修改img的src属性刷新图片时的图片缓存问题

问题:上传一张图片,通过js更新src属性刷新图片使其即时显示时, 当img的src当前的url与上次地址无变化时(只更改图片,名称不变,不同图片名称相同)图片不变化(仍显示原来的图片) 但通过...

HaierBrother ⋅ 18分钟前 ⋅ 0

Mysql

1.Jdbc Url 设置allowMultiQueries为true和false mysql的批量更新是要我们主动去设置的, 就是在数据库的连接url上设置一下,加上* &allowMultiQueries=true *即可。 参数名称 参数说明 缺省...

瑟青豆 ⋅ 21分钟前 ⋅ 0

mysql导出导入表结构与数据

当我们需要进行数据迁移时,mysql自带的mysqldump会是最好的方式。 1.导出某张表的结构和数据 首先,我们应当使用服务器,打开终端,连接到所需要导出的表所在的服务器上。执行命令: mysqld...

hengbao5 ⋅ 21分钟前 ⋅ 0

世界杯也走向“比拼”大数据的时代

《日本经济新闻》6月19日报道称,俄罗斯足球世界杯已于6月14日揭开战幕。作为第21次举办的足球世界杯,如何活用大数据有可能成为决定各支球队胜负的重要因素。从对阵球队的分析到战术建议,还...

加米谷大数据 ⋅ 22分钟前 ⋅ 0

金额转为千分制,金额转中文大写

金额转关为大写 js /** 数字金额大写转换(可以处理整数,小数,负数) */ function digitUppercase(n){ if(!n) reutrn "" let fraction = ['角', '分']; let digit = ['零', '壹', '贰', '叁', ...

YXMBetter ⋅ 25分钟前 ⋅ 0

开发利器JRebel部署SpringBoot项目

不要以为年纪轻轻就跌倒了人生谷底,未来还有更大的下降空间等着你。 idea下载和安装JRebel 激活JRebel 访问https://my.jrebel.com/ 使用facebook或twitter登录 勾选 Build project automati...

郑龙飞 ⋅ 30分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部