欢迎光临

我们一直在努力
当前位置:首页 > 编程技术 >

Android事件分发机制示例分析

日期:
后台-插件-广告管理-首页/栏目/内容广告位一(PC)
后台-插件-广告管理-首页/栏目/内容广告位一(手机)
  • android事件类型
public boolean> public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
           > @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }
public boolean superDispatchTouchEvent(MotionEvent evHnZDhjYKlNent) {
            return super.dispatchTouchEvent(event);
  }

mDecor是DecorView,是PhoneWindow的一个内部类,继承FrameLayout。

FrameLayout继承自ViewGroup,接下来看事件传递在ViewGroup中是如何处理的。事件传递的主要逻辑就在ViewGroup中。

接下来看ViewGroup,dispatchToucheEvent(MotionEvent ev)是如何对事件进行分发的。

public class ViewGroup {
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean handled = false;
        final int action = ev.getAction();
        final int actionMasked = action & MotionEvent.ACTIONhttp://_MASK;
        // Check for interception.
        //按下后,第一次调用时actionMasked=down,mFirstTouchtarget=null
        //一直按着 actionMasked=move, 如果mFirstTouchTarget!=null说明有子view处理了touch事件
        final boolean intercepted;
        if (actionMasked == MotionEvent.ACTION_DOWN
                || mFirstTouchTarget != null) {
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!disallowIntercept) {
                //调用子类复写的方法 如果为true表示拦截,false表示不拦截
                intercepted =>android
        //第一次按下时,判断view是否处理事件的标志
        boolean alreadyDispatchedToNewTouchTarget = false;
        //如果不拦截,则进入事件分发
        if (!canceled && !intercepted) {
            //注意,只有ACTION_DOWN时才会遍历子View
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                final int childrenCount = mChildrenCount;
                if (newTouchTarget == null && childrenCount != 0) {
                    final ArrayList<View> preorderedList = buildTouchDispatchChildList();
                    final View[] children = mChildren;
                    //开始遍历子view
                    for (int i = childrenCoupythonnt - 1; i >= 0; i--) {
                        final View child = getAndVerifyPreorderedView(
                                preorderedList, children, childIndex);
                        //isTransformedTouchPointInView 通过比对坐标,来判断事件是否落在了child上,
                        // true是,false不是
                        if (!canViewReceivePointerEvents(child)
                                || !isTransformedTouchPointInView(x, y, child, null)) {
                            ev.setTargetAccessibilityFocus(false);
                            // 如果事件没有落在child上,则跳过此次循环,执行下一次循环
                            continue;
                        }
                        //通过遍历TouchTarget链表查找TouchTarget,如果找到了,则break跳出循环
                        newTouchTarget = getTouchTarget(child);
                        if (newTouchTarget != null) {
                            // Child is already receiving touch within its bounds.
                            // Give it the new pointer in addition to the>public class View {
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean result = false;
        ListenerInfo li = mListenerInfo;
        //如果view设置了mOnTouchListener,先调用mOnTouchListener.onTouch,
        //如果返回true,则表示消费了此事件,不在向下传递,为啥这样说?那是因为,通过他的返回值,进行了逻辑判断
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
    http://    }
        //如果result为false,则调用View.onTouchEvent方法
        if (!result && onTouchEvent(event)) {
            result = true;
        }
        return result;
    }
    public boolean onTouchEvent(MotionEvent event) {
        switch (action) {
            case MotionEvent.ACTION_UP:
                if (mPerformClick == null) {
                    mPerformClick = new PerformClick();
                }
                if (!post(mPerformClick)) {
                    //调用performClick mOnClickListener.onClick()方法
                    performClickInternal();
                }
                break;
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            case MotionEvent.ACTION_MOVE:
                break;
        }
        return false;
    }
    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;
        }
        return result;
    }
}[!--empirenews.page--]

如果仔细看了ViewGroup和View事件分发逻辑代码。我们可以总结为以下几点。

1.ViewGroup接收到DispatchTouchEvent调用后,先调用了onInterceptTouchEvent,通过返回值进行判断是否对事件进行拦截。我们可以在代码中复写这个方法来进行事件的拦截。

2.down事件后,ViewGoup会遍历子View,找到处理Touch事件的View,并且缓存到了TouchTarget链表中,一次事件流中,只有down的时候才会进行子View的遍历。

只有做的好处提升了性能,缓存的链表中也是为了多点触摸,会有多个view响应触摸事件。

move事件时,则会从这个链表中进行遍历,通过调用dispatchTransformedTouchEvent方法进行事件的传递。

  • 在dispatchTransformedTouchEvent方法中,根据child的值是否为null进入不同的分发流程。

1)如果为null说明没有子view没有响应事件,则调用父类View的dispatchTouchEvent--->onTouchEvent方法。

2)如果child值不为null。则调用child的dispatchTouchEvent方法,

此时如果child是一个ViewGoup则还是执行ViewGoup中的分发逻辑,进行递归调用。

如果child是一个View,则调用View的dispatchTouchEvent--->onTouchEvent方法。

  • 在View的dispatchTouchEvent方法中:

1)listener的onTouch优先级要高于View的onTouchEvent

2)会先调用mOnTouchListener.onTouch方法,并根据返回值进行判断是否消费事件。

3)如果上面的返回值为false,则会调用View的onTouchEvent方法。

5.在View的onTouchEvent方法中UP事件时,才会调用View设置的onClickListener的监听事件。

这就是为什么了,同时给一个View设置了onTouch监听和lonClickListener监听时,当onTouch返回true无法调用onClick事件的原因。

到此这篇关于Android事件分发机制示例分析的文章就介绍到这了,更多相关Android事件分发内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

后台-插件-广告管理-首页/栏目/内容广告位二(PC)
后台-插件-广告管理-首页/栏目/内容广告位二(手机)
后台-插件-广告管理-内容广告位三(PC)
后台-插件-广告管理-内容广告位三(手机)

相关阅读

后台-插件-广告管理-内容广告位四(PC)
后台-插件-广告管理-内容广告位四(手机)

热门文章

后台-插件-广告管理-侧边广告位一(PC)
后台-插件-广告管理-侧边广告位一(手机)
  • HTML 表单组件实例代码

  • HTML 表单用于搜集不同类型的用户输入。下文通过代码给大家分享html 表单组件实例代码,感兴趣的朋友参考下吧 废话不多说了,直接给大家贴代码了,具体代码如下所示: <!DOCTYPE
  • html2canvas 将html代码转为图片的使用方法

  • 转换代码到图片使用 html2canvas,这是一个非常著名的从浏览器网页截图的开源库,使用很方便,功能也很强大。 使用 html2canvas http:// html2canvas 的使用非常简单,简单
  • HTML网页中插入视频的方法小结

  • 现在如果要在页面中使用video标签,需要考虑三种情况,支持Ogg Theora或者VP8(如果这玩意儿没出事的话)的(Opera、Mozilla、Chrome),支持H.264的(Safari、IE 9、Chrome),都不支持的(IE6、
  • HTML实现文本框只读不能修改其中的内容

  • 废话不多说了,直接给大家贴代码了,具体代码如下所示: <!--方法1:>http:// 当鼠标放不上就离开焦点 --> <input type="text" name="input1" value=http://www.cppcns.com/web
  • 移动端专用的meta标签设置大全

  • 前言 之前学习前端中,对meta标签的了解仅仅只是这一句。 <meta charset="UTF-8"> 但是打开任意的网站,其head标签内都有一列的meta标签。比如我们我们网站,但是自己却很不熟
后台-插件-广告管理-侧边广告位二(PC)
后台-插件-广告管理-侧边广告位二(手机)

最新文章

  • 在Asp.net core项目中使用WebSocket

  • 今天小试了一下在ASP.NET core中使用websocket,这里记录一下: 在 Startup 类的 Configure 方法中添加 WebSocket 中间件。 app.UseWebSockets(); 它也可以传入一些参数 app.Us
  • Vue快速理解事件绑定是什么

  • 目录一、监听事件二、事件修饰符1、stop修饰符阻止事件冒泡2、capture修饰符3、self修饰符4、prevent修饰符5、键盘事件修饰符6、鼠标事件修饰符一、监听事件 监听事件一般
  • C#实现模拟ATM自动取款机功能

  • 目录(1)关于用户帐号的类:Account(2)关于银行数据库的类:BankDatabase(3)关于ATM屏幕显示的类:Screen(4)关于ATM键盘的类:Keypad(5)关于进钞、出钞口的类:DepositSlot(6)关于ATM
  • Java设计模式之抽象工厂模式浅析讲解

  • 1.介绍 当系统准备为用户提供一系列相关对象,又不想让用户代码和这些对象形成耦合时,就可以使用抽象工厂模式。 2.如何实现 1)抽象产品--Car 2)具体产品--BYDCar、TSLCar 3)抽象
  • 如何动态替换Spring容器中的Bean

  • 目录动态替换Spring容器中的Bean原因方案实现Spring中的bean替换问题动态替换Spring容器中的Bean 原因 最近在编写单测时,发现使用 Mock 工具预定义 Service 中方法的行为特
  • C#优雅的实现INotifyPropertyChanged接口

  • INotifyPropertyChanged接口在wpF或WinFrom程序中使用还是经常用到,常用于通知界面属性变更。标准写法如下: class NotifandroidyObject : INotifyPropertyChanged {
后台-插件-广告管理-侧边广告位三(PC)
后台-插件-广告管理-侧边广告位三(手机)