Android事件分发机制(下) View的事件处理

综述

  在上篇文章Android中的事件分发机制(上)——ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析。在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将事件传递给ViewGroup的子View。并交由子View进行处理。那么现在就来分析一下子View接收到事件以后是如何处理的。

View的事件处理

  对于这里描述的View,它是ViewGroup的父类,并不包含任何的子元素。这也就意味着View无法再次向下对事件进行分发操作,因此在View中并不存在onInterceptTouchEvent方法,也不会对事件做出拦截操作。它所做的事情就是对所接收的事件进行处理。下面就开看一下View如何对事件进行处理的。
  既然ViewGroup将事件交由View的dispatchTouchEvent方。那么首先在这里就来看一下dispatchTouchEvent里面做了什么事情。

public boolean dispatchTouchEvent(MotionEvent event) { ...... if (onFilterTouchEventForSecurity(event)) { //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; } } ...... return result; }

  在View的dispatchTouchEvent方法中对事件处理的核心部分体现在上述代码中。onFilterTouchEventForSecurity方法表示当前接收事件的view是否处于被遮盖状态,View处于被遮盖状态表示当前View不位于顶部,该view被其它View所覆盖。如果当前View被遮盖,那么该View不会对事件进行处理。

public interface OnTouchListener { boolean onTouch(View v, MotionEvent event); } public void setOnTouchListener(OnTouchListener l) { getListenerInfo().mOnTouchListener = l; } ListenerInfo getListenerInfo() { if (mListenerInfo != null) { return mListenerInfo; } mListenerInfo = new ListenerInfo(); return mListenerInfo; }

  在结合上述一段代码可以看到,通过setOnTouchListener方法设置OnTouchListener以后,若是当前View处于可用状态,那么条件li != null && li.mOnTouchListener !=null && (mViewFlags & ENABLED_MASK) == ENABLED必然为true。这时候程序便会回调OnTouchListener中的onTouch方法,若是在onTouch方法中返回true,便不会在执行View的onTouchEvent方法。从这里我们能够看到,一旦设置了OnTouchListener,那么OnTouchListener的优先级要高于onTouchEvent。
  有一点需要注意,在程序中设置了OnTouchListener以后,对于OnTouchListener中的onTouch的返回值并不代表View中的dispatchTouchEvent方法所返回的值。在onTouch方法返回true的时候,表示事件成功被当前View所消耗,这时候result被置为true并且不再执行onTouchEvent,所以dispatchTouchEvent也就返回true。可是一旦在onTouch方法中返回false。这时候便会调用onTouchEvent方法,如果事件被onTouchEvent成功处理,并返回true,result依然会被置为true,dispatchTouchEvent自然而然的也就返回true。
  下面在进入View的onTouchEvent方法一探究竟。对于onTouchEvent方法里的内容比较多,在这里分段查看。

if ((viewFlags & ENABLED_MASK) == DISABLED) { if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { setPressed(false); } // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE); }

  在这里可以看出对于不可用的View,如果他们的一些点击事件可用的话,依然能够成功的消费事件,只是它不会为该事件做出响应。对于View的这些点击之间默认为不可用,但是对于不同的的View他们的默认值不一样。例如在ImageView中点击事件依然为不可用,但是在Button中点击事件为可用。当然如果手动为它们设置监听事件,那么这些监听事件都将会自动被设为可用状态。从如下源码中可以看出。

public void setOnClickListener(@Nullable OnClickListener l) { if (!isClickable()) { setClickable(true); } getListenerInfo().mOnClickListener = l; } public void setOnLongClickListener(@Nullable OnLongClickListener l) { if (!isLongClickable()) { setLongClickable(true); } getListenerInfo().mOnLongClickListener = l; } public void setOnContextClickListener(@Nullable OnContextClickListener l) { if (!isContextClickable()) { setContextClickable(true); } getListenerInfo().mOnContextClickListener = l; }   下面接着看OnTouchEvent里面代码。 if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } }

  这里首先判断是否对事件设置了代理,如果对事件设置了代理,便会执行TouchDelegate的onTouchEvent方法。mTouchDelegate默认值为null,可以通过View的setTouchDelegate方法来设置代理。对于TouchDelegate在后续的文章中在进行详细分析,在这里就不在过多描述。
  最后看一下View是如何处理事件的,对于接收的事件整个处理过程比较复杂,在这里就从宏观上来整体看一下它的处理机制。

if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) { switch (action) { case MotionEvent.ACTION_UP: ...... if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { // This is a tap, so remove the longpress check removeLongPressCallback(); // Only perform take click actions if we were in the pressed state if (!focusTaken) { // Use a Runnable and post this rather than calling // performClick directly. This lets other visual state // of the view update before click actions start. if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); } } } ...... break; ...... } return true; }

  如果View的点击事件处于可用状态的话,便会对于这些事件进行处理,并且返回true。当一个事件序列完成以后调用performClick方法,下面看下这个performClick方法。

public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); return result; }

  从上面代码中可以看出,如果我们设置了OnClickListener,便会调用它的onClick方法。从这一路下来我们可以看出对于View的onClick事件,在最后才会被调用,可见onClick的优先级是最低的。

总结

  在这里对View的事件处理做一下总结。在ViewGroup将事件分发到View以后。在View里面通过OnTouchListener的onTouch和View中的onTouchEvent这两个方法对事件进行处理。对于onTouch方法是View提供给用户的,方便用户自己处理触摸事件,而onTouchEvent是Android系统自己实现的接口。若是用户设置了OnTouchListener,Android系统会首先调用OnTouchListener的onTouch方法。若是在onTouch方法中返回true,就不在执行View的onTouchEvent方法。只有在onTouch中返回了false才会执行onTouchEvent。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-08-24 17:20:08

Android事件分发机制(下) View的事件处理的相关文章

Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

记得在前面的文章中,我带大家一起从源码的角度分析了Android中View的事件分发机制,相信阅读过的 朋友对View的事件分发已经有比较深刻的理解了. 还未阅读过的朋友,请先参考 Android事件分发机 制完全解析,带你从源码的角度彻底理解(上) . 那么今天我们将继续上次未完成的话题,从源码的 角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区 别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View和子

一篇文章彻底搞懂Android事件分发机制

本文讲的是一篇文章彻底搞懂Android事件分发机制,在android开发中会经常遇到滑动冲突(比如ScrollView或是SliddingMenu与ListView的嵌套)的问题,需要我们深入的了解android事件响应机制才能解决,事件响应机制已经是android开发者必不可少的知识.面试找工作的时候也是面试官经常会问的一个问题. 涉及到事件响应的常用方法构成 用户在手指与屏幕接触过程中通过MotionEvent对象产生一系列事件,它有四种状态: MotionEvent.ACTION_DOW

认识一下Android 事件分发机制

1.引子 由于Android是采用分层布局(可以想象成PS时的图层概念一样),这样才可以在有限大小的手机屏幕上完成一些复杂的操作.当手指点击屏幕开始,这些动作在各层之间如何传递?就引出了Android的事件分发机制.之所以称为事件,是由于在Android中将所有在屏幕的动作封装成3个事件 ACTION_DOWN:手指按下 ACTION_MOVE:手指在屏幕滑动 ACTION_UP:手指从屏幕抬起 每次都是从ACTION_DOWN开始,到ACTION_UP结束,中间伴随着ACTION_MOVE:有

Android事件分发机制

说在开头,之前项目中使用到了ListView和Button的组合,由于两者都有click事件,也意识到应该是Android的事件分发机制的原因.面试时也特意去恶补过,不过也是一知半解,此次因在项目中遇到该问题特意去详细了解一下. 引言 点击事件的分发机制由于主要发生在界面中,需要先了解Android系统的UI架构,如下图所示. 我们都知道Android程序的UI是由Activity这个组件构成的,而实际中是使用setContentView这个方法设置一个自定义布局的,这里的ContentView

Android事件分发机制源码和实例解析

1.事件分发过程的理解 1.1. 概述 1.2. 主要方法 1.3. 核心行为 1.4. 特殊情况 2.案例分析 2.1. 案例1:均不消费 down 事件 2.2. 案例2:View0 消费 down 事件 2.3. 案例3:ViewGroup2nd 消费 down 事件 3.down 事件分发图 1. 事件分发过程的理解 1.1. 概述 事件主要有 down(MotionEvent.ACTION_DOWN),move(MotionEvent.ACTION_MOVE),up(MotionEve

Android View 事件分发机制详解_Android

Android开发,触控无处不在.对于一些 不咋看源码的同学来说,多少对这块都会有一些疑惑.View事件的分发机制,不仅在做业务需求中会碰到这些问题,在一些面试笔试题中也常有人问,可谓是老生常谈了.我以前也看过很多人写的这方面的文章,不是说的太啰嗦就是太模糊,还有一些在细节上写的也有争议,故再次重新整理一下这块内容,十分钟让你搞明白View事件的分发机制. 说白了这些触控的事件分发机制就是弄清楚三个方法,dispatchTouchEvent(),OnInterceptTouchEvent(),o

Android View事件分发机制详解_Android

准备了一阵子,一直想写一篇事件分发的文章总结一下,这个知识点实在是太重要了. 一个应用的布局是丰富的,有TextView,ImageView,Button等,这些子View的外层还有ViewGroup,如RelativeLayout,LinearLayout.作为一个开发者,我们会思考,当点击一个按钮,Android系统是怎样确定我点的就是按钮而不是TextView的?然后还正确的响应了按钮的点击事件.内部经过了一系列什么过程呢? 先铺垫一些知识能更加清晰的理解事件分发机制: 1. 通过setC

30分钟搞清楚Android Touch事件分发机制_Android

Touch事件分发中只有两个主角:ViewGroup和View.Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理. View在ViewGroup内,ViewGroup也可以在其他ViewGroup内,这时候把内部的ViewGroup当成View来分析. ViewGroup的相关事件有三个:onInterceptTouchEvent.dispatchTouchEvent.onTouchEvent.View的相关事件只有两个:

Android事件传递机制

实验环境 OS X 10.9 Eclipse(ADT) Android源码版本:API Level 19(Android 4.4) Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和 双击,另外还包括单指操作和多指操作.所有这些都构成了Android中的事件响应 .总的来说,所有的事件都由如下三个部分作为基础: 按下(ACTION_DOWN) 移动(ACTION_MOVE) 抬起(ACTION_UP) 所有的操作事件首先必须执行的是按下操作(ACT