【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 )(一)

简介: 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 )(一)

文章目录

Android 事件分发 系列文章目录

前言

一、获取子组件

二、当前遍历的子组件的事件分发

三、ViewGroup 事件分发相关源码

前言

接上一篇博客 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 二 ) , 继续分析 ViewGroup 的事件分发机制后续代码 ;






一、获取子组件


之前已经按照 Z 轴深度 , 将组件进行排序 , 放在集合中 ;


倒序遍历排列好的组件 , 按照 Z 轴的上下顺序 , 先遍历的 Z 轴方向上 , 放在最上面的组件 , 也就是顶层组件 ;


for (int i = childrenCount - 1; i >= 0; i--) {


先获取组件索引 , 然后获取索引对应的子组件 ;


                     

// 获取索引
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            // 获取索引对应组件 
                            final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);


然后判定组件是否符合要求 :

调用 canViewReceivePointerEvents 方法 , 判定组件是否可见 , 会否处于动画中 ;


/**
     * Returns true if a child view can receive pointer events.
     * 判定控件是否可见 / 是否处于动画中 
     * @hide
     */
    private static boolean canViewReceivePointerEvents(@NonNull View child) {
        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                || child.getAnimation() != null;
    }


调用 isTransformedTouchPointInView 判定手指是否在控件上面 ;


 

/**
     * Returns true if a child view contains the specified point when transformed
     * into its coordinate space.
     * Child must not be null.
     * 判定手指是否触摸到了组件 , 是否在组件区域范围内 
     * @hide
     */
    protected boolean isTransformedTouchPointInView(float x, float y, View child,
            PointF outLocalPoint) {
        // 获取当前坐标 
        final float[] point = getTempPoint();
        point[0] = x;
        point[1] = y;
        transformPointToViewLocal(point, child);
        final boolean isInView = child.pointInView(point[0], point[1]);
        if (isInView && outLocalPoint != null) {
            outLocalPoint.set(point[0], point[1]);
        }
        return isInView;
    }


如果上面 3 33 个条件只要存在 1 11 个不满足 , 则不传递触摸事件 , 在遍历时直接 continue , 越过该控件 , 遍历下一个控件 ;


 

// X 控件范围 A , 如果手指按在 B 范围 , 不会触发 X 控件的事件 
        // 判定当前的组件是否可见 , 是否处于动画过程中 
        // ① canViewReceivePointerEvents 判定组件是否可见 , 会否处于动画 
        // ② isTransformedTouchPointInView 判定手指是否在控件上面 ; 
        // 上述两种情况 , 不触发事件 
                            if (!canViewReceivePointerEvents(child)
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                ev.setTargetAccessibilityFocus(false);
                                // 不触发事件 
                                continue;
                            }



ViewGroup | dispatchTouchEvent 方法相关源码 :


@UiThread
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
  ...
      // 倒序遍历 按照 Z 轴的上下顺序 , 排列好的组件 
      // 先遍历的 Z 轴方向上 , 放在最上面的组件 , 也就是顶层组件 
                        for (int i = childrenCount - 1; i >= 0; i--) {
                          // 获取索引
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            // 获取索引对应组件 
                            final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);
                            // If there is a view that has accessibility focus we want it
                            // to get the event first and if not handled we will perform a
                            // normal dispatch. We may do a double iteration but this is
                            // safer given the timeframe.
                            // 无障碍 辅助功能 
                            if (childWithAccessibilityFocus != null) {
                                if (childWithAccessibilityFocus != child) {
                                    continue;
                                }
                                childWithAccessibilityFocus = null;
                                i = childrenCount - 1;
                            }
        // X 控件范围 A , 如果手指按在 B 范围 , 不会触发 X 控件的事件 
        // 判定当前的组件是否可见 , 是否处于动画过程中 
        // ① canViewReceivePointerEvents 判定组件是否可见 , 会否处于动画 
        // ② isTransformedTouchPointInView 判定手指是否在控件上面 ; 
        // 上述两种情况 , 不触发事件 
                            if (!canViewReceivePointerEvents(child)
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                ev.setTargetAccessibilityFocus(false);
                                // 不触发事件 
                                continue;
                            }
        // 截止到此处 , 可以获取子组件进行操作   
  ...
  }
    /**
     * Returns true if a child view can receive pointer events.
     * 判定控件是否可见 / 是否处于动画中 
     * @hide
     */
    private static boolean canViewReceivePointerEvents(@NonNull View child) {
        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                || child.getAnimation() != null;
    }
    /**
     * Returns true if a child view contains the specified point when transformed
     * into its coordinate space.
     * Child must not be null.
     * 判定手指是否触摸到了组件 , 是否在组件区域范围内 
     * @hide
     */
    protected boolean isTransformedTouchPointInView(float x, float y, View child,
            PointF outLocalPoint) {
        // 获取当前坐标 
        final float[] point = getTempPoint();
        point[0] = x;
        point[1] = y;
        transformPointToViewLocal(point, child);
        final boolean isInView = child.pointInView(point[0], point[1]);
        if (isInView && outLocalPoint != null) {
            outLocalPoint.set(point[0], point[1]);
        }
        return isInView;
    }
}



源码路径 : /frameworks/base/core/java/android/view/ViewGroup.java



目录
相关文章
|
开发工具 Android开发 git
Windows下载android2.2完整源码(转)
Windows下载android2.2完整源码(转)
165 3
|
4月前
|
XML 搜索推荐 Android开发
Android改变进度条控件progressbar的样式(根据源码修改)
本文介绍了如何基于Android源码自定义ProgressBar样式。首先分析了系统源码中ProgressBar样式的定义,发现其依赖一张旋转图片实现动画效果。接着分两步指导开发者实现自定义:1) 模仿源码创建一个旋转动画XML文件(放置在drawable文件夹),修改图片为自定义样式;2) 在UI控件中通过`indeterminateDrawable`属性应用该动画。最终实现简单且个性化的ProgressBar效果,附带效果图展示。
253 2
|
5月前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
951 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
Java 开发工具 Android开发
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
136 4
|
Java Android开发
Android12 双击power键启动相机源码解析
Android12 双击power键启动相机源码解析
294 0
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
474 1
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
2169 1
|
API 开发工具 Android开发
Android源码下载
Android源码下载
1481 0
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
1880 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82