文档章节

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

没有更多内容

加载失败,请刷新页面

加载更多

linux中shell if 判断总结

UNIX Shell 里面比较字符写法 -eq 等于; -ne 不等于; -gt 大于; -lt 小于 ; -le 小于等于; -ge 大于等于; -z 空串; -n 非空串; = 两个字符相等; != 两个字符不等 无论什么编程语言都离不开条...

linuxprobe16
22分钟前
0
0
我是如何将博客转成PDF的

前言 只有光头才能变强 之前有读者问过我:“3y你的博客有没有电子版的呀?我想要份电子版的”。我说:“没有啊,我没有弄过电子版的,我这边有个文章导航页面,你可以去文章导航去找来看呀”...

Java3y
24分钟前
1
0
nginx的一些总结

Linux下安装Nginx完整教程及常见错误解决方案 1.Nginx安装环境 Nginx是C语言开发,建议在linux上运行,本教程使用Centos7.0作为安装环境. 1)gcc 安装nginx需要先将官网下载的源码进行编译,编译...

Yao--靠自己
31分钟前
1
0
Predicate函数式接口

Predicate接口主要用于流的筛选,比如在filter方法中传入Predicate判断。 作为函数式接口,这里居然有三个default方法,一个static方法,子孙满堂! 正统的接口方法,就是boolean test(T t)...

woshixin
32分钟前
1
0
sql 开窗函数

开窗函数:在开窗函数出现之前存在着很多用 SQL 语句很难解决的问题,很多都要通过复杂的相关子查询或者存储过程来完成。为了解决这些问题,在 2003 年 ISO SQL 标准加入了开窗函数,开窗函数...

hblt-j
42分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部