安卓之事件分发机制

这篇具有很好参考价值的文章主要介绍了安卓之事件分发机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

安卓之事件分发机制

简介

  • 事件分发的”事件“是指什么?
    答:点击事件(Touch事件)。
  • 当用户触摸屏幕(VIew或ViewGroup)时,将产生点击事件,即Touch事件。Touch事件的细节(如:触摸位置、事件等)会被封装成MotionEvent对象。
  • 常见的事件:
    • MotionEvent.ACTION_DOWN:按下。
    • MotionEvent.ACTION_UP:抬起。
    • MotionEvent.ACTION_MOVE:滑动。
    • MotionEvent.ACTION_CANCEL:结束事件(非正常情况)。
  • 事件列:指从手指接触屏幕至手指离开屏幕这个过程产生的一系列事件。
    • 一般情况下,事件列都是以DOWN事件开始、UP事件结束,中间有无数的MOVE事件。

本质

  • 事件分发的本质是将点击事件(MotionEvent)传递到某个具体的View进行处理的整个过程。即:事件传递的过程 = 分发过程

事件在哪些对象之间进行传递?

  • 答:Activity、ViewGroup、View。

事件分发的顺序是?

  • 答:Activity -> ViewGroup -> View。

事件分发过程由哪些方法协作完成?

  • 答:dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()。
    安卓之事件分发机制,安卓,android,java,开发语言

Activity的事件分发机制

当用户触摸屏幕时,底层的 InputManager 会将触摸事件封装为 MotionEvent 对象,然后将该对象传递给当前 Activity 的 PhoneWindow 对象。PhoneWindow 对象会将该 MotionEvent 传递给 DecorView 对象,DecorView 再传递给Atcivity的 dispatchTouchEvent() 方法进行事件分发或处理。Atcivity的 dispatchTouchEvent() 方法如下:文章来源地址https://www.toymoban.com/news/detail-606571.html

  •  public boolean dispatchTouchEvent(MotionEvent ev) {
         ...
         if (getWindow().superDispatchTouchEvent(ev)) {
             return true;
         }
         return onTouchEvent(ev);
     }
    

View的事件分发机制

  • 先看源码:
    •  public boolean dispatchTouchEvent(MotionEvent event) {
       	//...省略代码
       	//以下为核心代码:
       	//这里就是View在收到事件后的具体处理逻辑了,也就是ViewGroup调用了View的dispatchTouchEvent()方法把事件传递给了View
       	//先判断有没有给View设置OnTouchListener,如果有就执行OnTouchListener的onTouch()方法
       	//同时该方法有返回值表示事件有没有被消费,如果被消费了,result设置为true
       	//接着是判断如果没有被消费,则执行onTouchEvent()方法,这个方法中会沿着MotionEvent.ACTION_UP->performClickInternal()->performClick()->OnClickListener的onClick(),最后走到了点击监听的onClick()中。
       	//同时,onClick()也是用返回值表示事件有没有被消费。
       	if (onFilterTouchEventForSecurity(event)) {
               if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                   result = true;
               }
               //noinspection SimplifiableIfStatement
               ListenerInfo li = mListenerInfo;
               if (li != null && li.mOnTouchListener != null
                       && (mViewFlags & ENABLED_MASK) == ENABLED
                       && li.mOnTouchListener.onTouch(this, event)) {
                   result = true;
               }
      
               if (!result && onTouchEvent(event)) {
                   result = true;
               }
           }
           //...省略代码
       }
      
  • 简单总结:
    • View中按onTouch()->onTouckEvent()->onClick()的顺序执行。
    • 同理,你的自定义View如果需要处理事件分发,那就在dispatchTouchEvent()方法中。
  • 以上就是View中最核心的事件分发处理流程了,同时延伸出几个可以提问的问题:
    • ①问:onTouch()和onClick()谁先执行?
         答:源码的顺序就是先走onTouch(),再走onClick()。
    • ②问:onTouch()方法返回值的作用?
         答:不仅仅是onTouch()方法,几乎所有的方法返回true表示事件被消费,返回false表示事件未被消费,可以继续分发。
    • ③问:onTouchEvent()一定执行吗?
         答:不一定,如果设置了OnTouchListener,则先看onTouch()拦不拦截,不拦截才会走onTouchEvent()方法。同时如果是自定义View,还要看有没有重写dispatchTouchEvent()方法。
    • ④问:onTouch()和onTouchEvent一定会执行吗?
         答:不一定,首先事件得先传递到dispatchTouchEvent()中,其次看各种条件是否能通过。
    • ⑤问:如何分析事件分发冲突?
         答:就是查看对应的控件的dispatchTouchEvent()是怎么么处理的,看事件有没有传递进去,传递进去后又是在哪消费的。
    • ⑥问:
    •     答:

Activity的事件分发机制

  • 先看源码:
    •  //事件是怎么传递到Activity的dispatchTouchEvent()方法中的?
       //		
       //Activity中进行分发:
       //		这里调用沿着getWindow().superDispatchTouchEvent(ev)
       //					->Window的唯一实现类PhoneWindow的mDecor.superDispatchTouchEvent(event)
       //					->DecorView的super.dispatchTouchEvent(event),
       //		最后传递到ViewGroup中,ViewGroup又进行事件分发。
       //
       //如果事件在Activity->ViewGroup->View整个传递过程中没有被处理,
       //最后又交回Activity的onTouchEvent()进行处理,
       //再如果Activity也不处理,那只能交给系统处理了。
       public boolean dispatchTouchEvent(MotionEvent ev) {
           if (ev.getAction() == MotionEvent.ACTION_DOWN) {
               onUserInteraction();
           }
           if (getWindow().superDispatchTouchEvent(ev)) {
               return true;
           }
           return onTouchEvent(ev);
       }
      

ViewGroup的事件分发机制

  • 先看源码:
    •  //第一块:ViewGroup每次事件分发时,都需调用onInterceptTouchEvent()询问是否拦截事件。
       //这里两个关键的地方:disallowIntercept和onInterceptTouchEvent()。
       //		disallowIntercept:是否禁用事件拦截的功能(默认是false),可通过调用requestDisallowInterceptTouchEvent()修改。
       //		onInterceptTouchEvent():
       //			a.若在onInterceptTouchEvent()中返回false,即当前ViewGroup不拦截事件。
       // 		b. 若在onInterceptTouchEvent()中返回true,即拦截事件。
       //			这个方法中一般就是解决事件分发冲突的,本质就是事件拦不拦截,交由谁处理。
       final boolean intercepted;
       if (actionMasked == MotionEvent.ACTION_DOWN
               || mFirstTouchTarget != null) {
           final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
           if (!disallowIntercept) {
               intercepted = onInterceptTouchEvent(ev);
               ev.setAction(action);
           } else {
               intercepted = false;
           }
       } else {
           intercepted = true;
       }
       
       //第二块:分发事件,看哪个子View处理事件
       //通过for循环,遍历当前ViewGroup下的所有子View,根据点击的位置判断当前遍历的View是不是正在点击的View,从而找到当前被点击的View。
       //dispatchTransformedTouchEvent()方法:内部根据传入的childView是否为空来决定调用当前View还是子View的dispatchTouchEvent()方法。
       if (!canceled && !intercepted) {
       	//..省略代码
          for (int i = childrenCount - 1; i >= 0; i--) {
              if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                  mLastTouchDownTime = ev.getDownTime();
                  if (preorderedList != null) {
                      // childIndex points into presorted list, find original index
                      for (int j = 0; j < childrenCount; j++) {
                          if (children[childIndex] == mChildren[j]) {
                              mLastTouchDownIndex = j;
                              break;
                          }
                      }
                  } else {
                      mLastTouchDownIndex = childIndex;
                  }
                  mLastTouchDownX = ev.getX();
                  mLastTouchDownY = ev.getY();
                  newTouchTarget = addTouchTarget(child, idBitsToAssign);
                  alreadyDispatchedToNewTouchTarget = true;
                  break;
              }
              ev.setTargetAccessibilityFocus(false);
          }
       }
       
       //第三块:
       //执行事件。
       if (mFirstTouchTarget == null) {
           // No touch targets so treat this as an ordinary view.
           handled = dispatchTransformedTouchEvent(ev, canceled, null,
                   TouchTarget.ALL_POINTER_IDS);
       } else {
       	//...省略代码
       }
      

到了这里,关于安卓之事件分发机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter中为控件添加交互,带你一起探究Android事件分发机制

    ), ); } } 代码运行效果如图: 2.父widget管理widget的状态 对于父widget来说,管理状态并告诉其子widget何时更新通常是最有意义的。 例如,IconButton允许您将图标视为可点按的按钮。 IconButton是一个无状态的小部件,因为我们认为父widget需要知道该按钮是否被点击来采取相应的处理

    2024年04月11日
    浏览(42)
  • Android-高级-UI-进阶之路-(二)-深入理解-Android-8-0-View-触摸事件分发机制,查漏补缺

    我们看到内部又调用了父类 dispatchTouchEvent 方法, 所以最终是交给 ViewGroup 顶级 View 来处理分发了。 顶级 View 对点击事件的分发过程 在上一小节中我们知道了一个事件的传递流程,这里我们就大致在回顾一下。首先点击事件到达顶级 ViewGroup 之后,会调用自身的 dispatchTouchE

    2024年04月14日
    浏览(67)
  • Android 安卓开发语言kotlin与Java该如何选择

            如今在Android开发中,应用层开发语言主要是Java和Kotlin,Kotlin是后来加入的,主导的语言还是Java。kotlin的加入仿佛让会kotlin语言的开发者更屌一些,其实不然。         有人说kotlin的引入是解决开发者复杂的逻辑,并且对空指针控制的比较友好,但是我们在开

    2024年02月11日
    浏览(61)
  • SpringBoot源码分析(三):SpringBoot的事件分发机制

    通过解读 Springboot 的事件分发源码,了解一下几个问题: Springboot 注册事件监听器有几种方式,分别是什么? 什么情况下注册的事件监听会失效(接收不到Springboot事件)? Springboot 利用的哪一个类做的事件分发操作? Spring 是如何利用泛型做到的事件分发? 怎么自定义 lis

    2024年02月10日
    浏览(61)
  • Android 事件分发介绍

    目录 一、目的 二、环境 三、相关概念 3.1 事件分发 四、详细设计 4.1应用布局 4.1.1 应用布局结构 4.1.2 LayoutInspector 4.2 关键View方法 4.2.1 相关View 4.2.2 相关方法 4.2.3 View与方法关系 4.3 事件分发概念图 4.3.1 事件分发类图 4.3.2 事件分发模型图 4.4 Activity组件 4.4.1 Activity-dispatchTouch

    2024年02月03日
    浏览(40)
  • Android 事件分发

    本篇文章主要简单介绍下Android中的事件分发,和大家一起学习,进步,有问题也希望大家及时指证修改. 1: onClick和OnTouch 首先我们在单独的activity中添加个按钮button.增加点击事件setOnClickListener: 接着添加OnTouch: 我们执行下点击事件.可以看到输出如下: 2024-04-09 20:54:11.219 17770-17770/?

    2024年04月11日
    浏览(50)
  • Android事件分发-基础原理和场景分析

    作者:京东零售 郭旭锋 和其他平台类似,Android 中 View 的布局是一个树形结构,各个 ViewGroup 和 View 是按树形结构嵌套布局的,从而会出现用户触摸的位置坐标可能会落在多个 View 的范围内,这样就不知道哪个 View 来响应这个事件,为了解决这一问题,就出现了事件分发机制

    2023年04月21日
    浏览(41)
  • Android进阶 View事件体系(二):从源码解析View的事件分发

    本篇文章为总结View事件体系的第二篇文章,前一篇文章的在这里:Android进阶 View事件体系(一):概要介绍和实现View的滑动 本篇文章将专注于介绍View的点击事件的分发,介绍的内容主要有: 点击事件的传递原则 解析Activity的构成 源码解析View的事件分发 源码解析View对点击

    2024年02月06日
    浏览(46)
  • [Android 13]Input系列--触摸事件在应用进程的分发和处理

    hongxi.zhu 2023-7-21 Android 13 前面我们已经梳理了input事件在native层的传递,这一篇我们接着探索input事件在应用中的传递与处理,我们将按键事件和触摸事件分开梳理,这一篇就只涉及触摸事件。 一、事件的接收 从前面的篇幅我们知道,framework native层 InputDispatcher 向应用通过s

    2024年02月15日
    浏览(37)
  • 鸿蒙Harmony应用开发—ArkTS声明式开发(自定义事件分发)

    ArkUI在处理触屏事件时,会在触屏事件触发前进行按压点和组件区域的触摸测试,来收集需要响应触屏事件的组件,再基于触摸测试结果分发相应的触屏事件。在父节点,开发者可以通过onChildTouchTest决定如何让子节点去做触摸测试,影响子组件的触摸测试,最终影响后续的触

    2024年04月14日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包