文档章节

分享磨砺营马剑威老师讲解-源码解析View事件的分发机制

磨砺营
 磨砺营
发布于 2016/07/27 09:49
字数 822
阅读 1
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

首先,Android中View的事件分发机制有3个重要的方法

dispatchTouchEvent()onInterceptTouchEvent()onTouchEvent()

先来看dispatchTouchEvent()这个方法

public boolean dispatchTouchEvent(MotionEvent event) {

    if (!onFilterTouchEventForSecurity(event)) {

        return false;

    }



    if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&

            mOnTouchListener.onTouch(this, event)) {

        return true;

    }

    return onTouchEvent(event);

}

第一个判断指的是当前View被其它窗口覆盖,直接返回false,第二个判断首先判断mOnTouchListener不为null,并且view是enable的状态,然后 mOnTouchListener.onTouch(this, event)返回true,这三个条件如果都满足,直接return true ; 也就是下面的onTouchEvent(event)不会被执行了;

这个mOnTouchListener其实就是我们设置的View事件

public void setOnTouchListener(OnTouchListener l) {

    mOnTouchListener = l;

}

如果设置了View的事件setOnTouchListener,并且return true,那么View自己的onTouchEvent就不会被执行了,那么如果我们return false呢?看下面

看一下onTouchEvent()的源码

public boolean onTouchEvent(MotionEvent event) {

    final int viewFlags = mViewFlags;



    if ((viewFlags & ENABLED_MASK) == DISABLED) {

        // 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));

    }



    if (mTouchDelegate != null) {

        if (mTouchDelegate.onTouchEvent(event)) {

            return true;

        }

    }



    if (((viewFlags & CLICKABLE) == CLICKABLE ||

            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {

        switch (event.getAction()) {

            case MotionEvent.ACTION_UP:

                boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;

                if ((mPrivateFlags & PRESSED) != 0 || prepressed) {

                    // take focus if we don't have it already and we should in

                    // touch mode.

                    boolean focusTaken = false;

                    if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {

                        focusTaken = requestFocus();

                    }



                    if (!mHasPerformedLongPress) {

                        // 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();

                            }

                        }

                    }



                    if (mUnsetPressedState == null) {

                        mUnsetPressedState = new UnsetPressedState();

                    }



                    if (prepressed) {

                        mPrivateFlags |= PRESSED;

                        refreshDrawableState();

                        postDelayed(mUnsetPressedState,

                                ViewConfiguration.getPressedStateDuration());

                    } else if (!post(mUnsetPressedState)) {

                        // If the post failed, unpress right now

                        mUnsetPressedState.run();

                    }

                    removeTapCallback();

                }

                break;



            case MotionEvent.ACTION_DOWN:

                if (mPendingCheckForTap == null) {

                    mPendingCheckForTap = new CheckForTap();

                }

                mPrivateFlags |= PREPRESSED;

                mHasPerformedLongPress = false;

                postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());

                break;



            case MotionEvent.ACTION_CANCEL:

                mPrivateFlags &= ~PRESSED;

                refreshDrawableState();

                removeTapCallback();

                break;



            case MotionEvent.ACTION_MOVE:

                final int x = (int) event.getX();

                final int y = (int) event.getY();



                // Be lenient about moving outside of buttons

                int slop = mTouchSlop;

                if ((x < 0 - slop) || (x >= getWidth() + slop) ||

                        (y < 0 - slop) || (y >= getHeight() + slop)) {

                    // Outside button

                    removeTapCallback();

                    if ((mPrivateFlags & PRESSED) != 0) {

                        // Remove any future long press/tap checks

                        removeLongPressCallback();



                        // Need to switch from pressed to not pressed

                        mPrivateFlags &= ~PRESSED;

                        refreshDrawableState();

                    }

                }

                break;

        }

        return true;

    }



    return false;

}

if ((viewFlags & ENABLED_MASK) == DISABLED)如果当前View是Disabled状态且是可点击则会消费掉事件(return true);

这里有个最重要的方法是 if (((viewFlags & CLICKABLE) == CLICKABLE ||

            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)),如果短按或长按,就判断事件类型,有3个event状态,分别是

MotionEvent.ACTION_DOWN

MotionEvent.ACTION_MOVE

MotionEvent.ACTION_UP

onInterceptTouchEvent()方法是在dispatchTouchEvent里面调用:

public boolean dispatchTouchEvent(Motion e){ boolean result=false; if(onInterceptTouchEvent(e)){ //如果当前View截获事件,那么事件就会由当前View处理,即调用onTouchEvent() result=onTouchEvent(e); }else{ //如果不截获那么交给其子View来分发 result=child.dispatchTouchEvent(e); } return result;}

从以上可以看出,这三个方法的联系。onInterceptTouchEvent()方法在dispatchTouchEvent中调用,来判断自己是否需要截取事件,如果该方法返回为true,那么View将消费该事件,即会调用onTouchEvent()方法。如果返回false,那么通过调用子View的dispatchTouchEvent()将事件交由子View来处理。

onTouchEvent()和onInterceptTouchEvent()一样也是在dispatchTouchEvent中调用的。用来处理点击事件,包括ACTION_DOWN,ACTION_MOVE,ACTION_UP。如果返回结果为false表示不消费该事件,并且也不会截获接下来的事件序列。如果返回为true表示当前View消费该事件。

本文出自微信公众号mjw-java,更多内容请关注微信公众号或访问网站www.moliying.com

磨砺营
粉丝 7
博文 80
码字总数 97977
作品 0
昌平
私信 提问
加载中
请先登录后再评论。
Netty那点事(三)Channel与Pipeline

Channel是理解和使用Netty的核心。Channel的涉及内容较多,这里我使用由浅入深的介绍方法。在这篇文章中,我们主要介绍Channel部分中Pipeline实现机制。为了避免枯燥,借用一下《盗梦空间》的...

黄亿华
2013/11/24
2W
22
beego API开发以及自动化文档

beego API开发以及自动化文档 beego1.3版本已经在上个星期发布了,但是还是有很多人不了解如何来进行开发,也是在一步一步的测试中开发,期间QQ群里面很多人都问我如何开发,我的业余时间实在...

astaxie
2014/06/25
2.7W
22
Nutch学习笔记4-Nutch 1.7 的 索引篇 ElasticSearch

上一篇讲解了爬取和分析的流程,很重要的收获就是: 解析过程中,会根据页面的ContentType获得一系列的注册解析器, 依次调用每个解析器,当其中一个解析成功后就返回,否则继续执行下一个解...

强子哥哥
2014/06/26
712
0
程序猿媛一:Android滑动翻页+区域点击事件

滑动翻页+区域点击事件 ViewPager+GrideView 声明:博文为原创,文章内容为,效果展示,思路阐述,及代码片段。文尾附注源码获取途径。 转载请保留原文出处“http://my.oschina.net/gluoyer...

花佟林雨月
2013/11/09
4.2K
1
数据库代码辅助工具--MaoCaiJun.Database

MaoCaiJun.DataBase 是一个用于 Microsoft Visual Studio 的数据库代码生成组件。它是基于 xml 文件的代码创建工具,支持sql2000,sql2005,sql2008,access, SQLite MaoCaiJun.Database 数据库...

mccj
2013/02/06
2.3K
1

没有更多内容

加载失败,请刷新页面

加载更多

数据库高频面试点,事务/乐观锁/悲观锁/CAS/MySQL存储引擎

事务的ACID特性是什么? 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用; 一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读...

osc_45536bvu
58分钟前
16
0
大数据BI软件助力企业数字化转型

当下,「新基建」势头正盛,随着“新基建”成为热议话题,数字化也随之成为企业面临的新机遇和新挑战。新基建的核心就是数据,数据是数字经济和企业数字化转型的生产要素和发展动力。 再看看...

osc_0boqdoe2
59分钟前
7
0
凯旋创投来志刚:基因治疗新时代,大戏刚刚开始

  2017 年,全球第一个基因治疗方法 CAR-T 细胞药物 Kymriah 获得 FDA 上市批准,从此掀起了基因治疗的热潮。随着相关技术和政策的不断成熟,基因治疗市场也随之扩大。根据德勤发布的《引领...

osc_k3vwonkw
今天
10
0
LightningChart.NET使用两个BarSeries创建简单的2D图表

本教程介绍了如何使用两个BarSeries创建简单的2D图表。 BarSeries将数据值表示为矩形条,并且可以用于以非常清晰的方式可视化数据之间的差异和方差。 在本教程中,BarSeries用于表示两年期间...

roffey
今天
0
0
Mybatis trim 标签的 2 个妙用!

云栖号资讯:【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! mybatis的trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼...

osc_x03qsedc
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部