文档章节

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

没有更多内容

加载失败,请刷新页面

加载更多

Vue重要知识小结

vue sync修饰 (1)双向数据绑定,父子组件之间信息的交互 1⃣️在自组件中使用this.emmit('toFather'),子组件产生一个tofather事件,然后在父组件中通过@进行监听,那么可以实现通信过程 2⃣...

peakedness丶
37分钟前
1
0
1024我们的码农节-向自己致敬!

一、blog主有话要说 作为(真正)入赘程序届的第一年, 对明天的1024码农节有很多话想说.比如: 给各位辛苦大佬们讲几个咱们程序届段子 给自己立一个flag, 明年的1024争取少掉点甚至不掉头发! ...

Ala6
39分钟前
10
0
solr使用规范

0. 目的 规范solr设计、用法,避免bug,提高性能 1. 设计规范 solr的用途是查询,不是存储,建议查询结果尽量都为id主键,而后再拿该id主键到缓存或者db中再查询相关信息,例如:请勿将经销商...

andersChow
51分钟前
1
0
11-《深度拆解JVM》之Java对象的内存布局

一、问题引入 在 Java 程序中,我们拥有多种新建对象的方式。除了最为常见的 new 语句之外,我们还可以通过反射机制、Object.clone 方法、反序列化以及 Unsafe.allocateInstance 方法来新建对...

飞鱼说编程
55分钟前
1
0
Windows Install Docker

win7、win8 win7、win8 等需要利用 docker toolbox 来安装,国内可以使用阿里云的镜像来下载,下载地址:http://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/ docker toolbox...

linuxprobe16
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部