文档章节

分享磨砺营马剑威老师讲解-源码解析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

© 著作权归作者所有

共有 人打赏支持
磨砺营
粉丝 5
博文 80
码字总数 97977
作品 0
昌平
如何编写一个够逼格的标题栏(磨砺营马剑威Android)

然后是代码的实现: public class ToolBarActivity extends AppCompatActivity { 这里设置notitle主题 这里获取toolbar后,对其进行一系列的设置,颜色,字体等等。 这里是设置toolbar右侧的...

磨砺营
2016/08/18
21
0
Android做好项目,再去面试(磨砺营马剑威Android)

【威哥说】磨砺营靠什么比别人优秀?不仅仅是教学靠谱,老师靠谱,更重要的是咱们在磨砺营做的都是真实的商业项目,由磨砺营自主研发的项目,今天我们就来了解一下咱们磨砺营IT教育的实训项目...

磨砺营
2016/09/01
25
0
Android6.0源码解读之Activity点击事件分发机制

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

mynameishuangshuai
2016/10/23
0
0
Android6.0源码解读之View点击事件分发机制

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

mynameishuangshuai
2016/10/23
0
0
Android6.0源码解读之ViewGroup点击事件分发机制

本篇博文是Android点击事件分发机制系列博文的第三篇,主要是从解读ViewGroup类的源码入手,根据源码理清ViewGroup点击事件分发原理,明白ViewGroup和View点击事件分发的关系,并掌握ViewGro...

mynameishuangshuai
2016/10/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java工程师用spring boot和web3j构建以太坊区块链应用

区块链最近IT世界的流行语之一。这项有关数字加密货币的技术,并与比特币一起构成了这个热门的流行趋势。它是去中心化的,不可变的分块数据结构,这是可以安全连接和使用的密码算法。在这种结...

笔阁
9分钟前
1
0
聊聊sentinel的SentinelWebAutoConfiguration

序 本文主要研究一下sentinel的SentinelWebAutoConfiguration SentinelWebAutoConfiguration spring-cloud-alibaba-sentinel-autoconfigure-0.2.0.BUILD-SNAPSHOT-sources.jar!/org/springf......

go4it
11分钟前
0
0
java ArrayList 根据对象内的属性排序

//根据修改时间排序Comparator com = new Comparator<ReleaseInfo>() {public int compare(ReleaseInfo reInfo1, ReleaseInfo reInfo2) { //return reInfo2.getModifyTime().c......

成长中的小白
11分钟前
0
0
PowerDesigner p f m

(非原创) P:PirmaryKey 主键 F:ForeignKey 外键 M:Mandatory 强制要求(不能为空) 主键: 主键是数据表的唯一索引,比如学生表里有学号和姓名,姓名可能有重名的,但学号确是唯一的,你要从...

森火
11分钟前
0
0
Nexus Repository Manager 搭建私有docker仓库

Nexus Repository Manager 搭建私有docker仓库 2018年05月08日 14:44:23 阅读数:115 1.下载nexus3的镜像: docker pull sonatype/nexus3 2.使用镜像启动一个容器: docker run -d --name n...

linjin200
12分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部