aosp14分屏分割线区域部分深入剖析-framework实战干货

背景:

原来在学习分屏课程期间,当时没有对分屏分割线的区域部分进行详细介绍。
本篇文章就针对这个块的知识进行详细的补充讲解,首先可以通过下图所示分割线情况,这样有一个初步的认识
在这里插入图片描述

简单说分屏情况下分割线是可以拖拉到不同的档位区域,而且竖屏和横屏的分割线区域还有差别,比如竖屏可以有5分档,而横屏只有3分档。

注意:这个5分档,3分档一般来说包含边际的两个分档,但是边际的分档一般看不见,所以说真的可以见分档线其实都需要减2,比如竖屏可见是3个分割线,横屏1各分割线
在这里插入图片描述

剖析分割线构建SnapTarget源码

代码位置:
frameworks/base/core/java/com/android/internal/policy/DividerSnapAlgorithm.java

这个DividerSnapAlgorithm是专门管理分割线位置相关的算法类
分割线的代表类SnapTarget:


    /**
     * Represents a snap target for the divider.
     */
    public static class SnapTarget {
        public static final int FLAG_NONE = 0;

        /** If the divider reaches this value, the left/top task should be dismissed. */
        public static final int FLAG_DISMISS_START = 1;

        /** If the divider reaches this value, the right/bottom task should be dismissed */
        public static final int FLAG_DISMISS_END = 2;

        /** Position of this snap target. The right/bottom edge of the top/left task snaps here. */
        public final int position;

        /**
         * Like {@link #position}, but used to calculate the task bounds which might be different
         * from the stack bounds.
         */
        public final int taskPosition;

        public final int flag;

        public boolean isMiddleTarget;

        /**
         * Multiplier used to calculate distance to snap position. The lower this value, the harder
         * it's to snap on this target
         */
        private final float distanceMultiplier;

        public SnapTarget(int position, int taskPosition, int flag) {
            this(position, taskPosition, flag, 1f);
        }

        public SnapTarget(int position, int taskPosition, int flag, float distanceMultiplier) {
            this.position = position;
            this.taskPosition = taskPosition;
            this.flag = flag;
            this.distanceMultiplier = distanceMultiplier;
        }
    }

几个重要参数:

position 即代表分割线位置

flag 主要代表是来针对区分边际分割线,主要有FLAG_DISMISS_START(上)和FLAG_DISMISS_END(下),其他都是FLAG_NONE

distanceMultiplier 这个属于一个放大因子,就是针对首尾分割线的有到达距离的放大,让首尾分割线不会因为不小心误触很容易进入

具体计算分割线方法如下:

private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
        mTargets.clear();
        int dividerMax = isHorizontalDivision
                ? mDisplayHeight
                : mDisplayWidth;
        int startPos = -mDividerSize;
        if (dockedSide == DOCKED_RIGHT) {
            startPos += mInsets.left;
        }
        //首先添加SnapTarget.FLAG_DISMISS_START的SnapTarget
        mTargets.add(new SnapTarget(startPos, startPos, SnapTarget.FLAG_DISMISS_START,
                0.35f));
        switch (mSnapMode) {//这里需要根据mSnapMode来分别创建分割情况
            case SNAP_MODE_16_9://正常竖屏就是SNAP_MODE_16_9,一般会创建3个分割线
                addRatio16_9Targets(isHorizontalDivision, dividerMax);
                break;
            case SNAP_FIXED_RATIO:
                addFixedDivisionTargets(isHorizontalDivision, dividerMax);
                break;
            case SNAP_ONLY_1_1://正常横屏就是SNAP_ONLY_1_1,所以只有中间一个分割线
                addMiddleTarget(isHorizontalDivision);
                break;
            case SNAP_MODE_MINIMIZED:
                addMinimizedTarget(isHorizontalDivision, dockedSide);
                break;
        }
        
        //最后添加SnapTarget.FLAG_DISMISS_END的SnapTarget
        mTargets.add(new SnapTarget(dividerMax, dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f));
    }

参数isHorizontalDivision,代表是当前分割线是横着显示还是竖着显示,所以这里注意不是指的横竖屏幕,刚好是相反的,竖屏分割线是横着显示isHorizontalDivision =true,横屏isHorizontalDivision=false。

mSnapMode这个变量是在DividerSnapAlgorithm构造时候从res中config获取的
在这里插入图片描述通过搜索dockedStackDividerSnapMode发现如下:在这里插入图片描述竖屏值一般是0,横屏值一般是2

在这里插入图片描述
先看看简单的SNAP_ONLY_1_1的实现方法直接就是addMiddleTarget

    private void addMiddleTarget(boolean isHorizontalDivision) {
        int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
                mInsets, mDisplayWidth, mDisplayHeight, mDividerSize);
        mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
    }
   public static int calculateMiddlePosition(boolean isHorizontalDivision, Rect insets,
            int displayWidth, int displayHeight, int dividerSize) {
        int start = isHorizontalDivision ? insets.top : insets.left;
        int end = isHorizontalDivision
                ? displayHeight - insets.bottom
                : displayWidth - insets.right;
        return start + (end - start) / 2 - dividerSize / 2;
    }

这里可以看出来就是通过calculateMiddlePosition计算出来中间位置positon,再用这个positon构建对应的SnapTarget添加到mTargets。

同理看看竖屏的3个snap的计算方法addRatio16_9Targets

private void addRatio16_9Targets(boolean isHorizontalDivision, int dividerMax) {
    int start = isHorizontalDivision ? mInsets.top : mInsets.left;
    int end = isHorizontalDivision
            ? mDisplayHeight - mInsets.bottom
            : mDisplayWidth - mInsets.right;
    int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
    int endOther = isHorizontalDivision
            ? mDisplayWidth - mInsets.right
            : mDisplayHeight - mInsets.bottom;
    float size = 9.0f / 16.0f * (endOther - startOther);
    int sizeInt = (int) Math.floor(size);
    int topPosition = start + sizeInt;
    int bottomPosition = end - sizeInt - mDividerSize;
    //注意这里计算了topPosition,bottomPosition两个位置,这里就是3分割线的上下分割线位置
    addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax);
}

  private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
            int bottomPosition, int dividerMax) {
        maybeAddTarget(topPosition, topPosition - getStartInset());
        addMiddleTarget(isHorizontalDivision);
        maybeAddTarget(bottomPosition,
                dividerMax - getEndInset() - (bottomPosition + mDividerSize));
    }

这里addRatio16_9Targets核心就是计算出来了topPosition,bottomPosition,然后再使用addNonDismissingTargets方法进行构建SnapTarget。

核心看看这里的topPosition,bottomPosition是怎么计算的,刚好也可以解释为啥这里名字有16_9这个字符,其实本质就是计算个topPosition位置,拿竖屏来举例的话,这里因为想要屏幕宽度固定的,为了美观程度,所以一般topPosition这个区域要固定为一个16:9区域

在这里插入图片描述

addNonDismissingTargets方法主要就是有了topPosition,bottomPosition,在额外加上个middle,这样整体3个SnapTarget就构造成功。

创建后的分割线SnapTarget都会被放入到mTargets这个集合中去。

寻找合适分割线算法

上面已经分析出了分割线的几个SnapTarget,这些SnapTarget都是有固定位置的,那么接下来分析一下分割线如何到对应的SnapTarget。

外部传递一个比例值情况
一般这种情况是在启动分屏时候,需要设置好一个上下分屏比例ratio,主要通过如下方法:

/** Updates divide position and split bounds base on the ratio within root bounds. */
public void setDivideRatio(float ratio) {
    final int position = isLandscape()
            ? mRootBounds.left + (int) (mRootBounds.width() * ratio)
            : mRootBounds.top + (int) (mRootBounds.height() * ratio);
    final DividerSnapAlgorithm.SnapTarget snapTarget =
            mDividerSnapAlgorithm.calculateNonDismissingSnapTarget(position);
    setDividePosition(snapTarget.position, false /* applyLayoutChange */);
}

可以看到这里会先根据ratio计算出一个位置position,但是这个position并不是直接的SnapTarget的position,需要把这个position传递到calculateNonDismissingSnapTarget方法计算出SnapTarget,然后在使用SnapTarget的position。
即比如传递ratio进去是0.25,那么计算的position就是2960 * 0.25 = 740,但是正常的top的SnapTarget的position一般是810+84 = 894。
看看这里的calculateNonDismissingSnapTarget方法

   public SnapTarget calculateNonDismissingSnapTarget(int position) {
        SnapTarget target = snap(position, false /* hardDismiss */);//主要调用snap
        if (target == mDismissStartTarget) {
            return mFirstSplitTarget;
        } else if (target == mDismissEndTarget) {
            return mLastSplitTarget;
        } else {
            return target;
        }
    }

看看snap方法:

    private SnapTarget snap(int position, boolean hardDismiss) {
        if (shouldApplyFreeSnapMode(position)) {
            return new SnapTarget(position, position, SnapTarget.FLAG_NONE);
        }
        int minIndex = -1;
        float minDistance = Float.MAX_VALUE;
        int size = mTargets.size();
        for (int i = 0; i < size; i++) {
            SnapTarget target = mTargets.get(i);
            float distance = Math.abs(position - target.position);
            if (hardDismiss) {
                distance /= target.distanceMultiplier;
            }
            if (distance < minDistance) {//这里会计算传递进来position和SnapTarget.position的距离
                minIndex = i;
                minDistance = distance;
            }
        }
        return mTargets.get(minIndex);
    }

这里snap方法本质就是根据传递进来的position,与mTargets集合的所有position进行比较距离,离谁最近就选谁。

更多framework详细代码和资料参考如下链接
投屏专题部分:

https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg

hal+perfetto+surfaceflinger

https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
其他课程七件套专题:在这里插入图片描述
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频试看:
https://www.bilibili.com/video/BV1wc41117L4/

参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615

更多framework假威风耗:androidframework007

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891907.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

社交媒体对人际关系的影响:Facebook的案例分析

随着社交媒体的快速发展&#xff0c;人们的沟通方式和人际关系发生了深刻变化。作为全球最大的社交网络之一&#xff0c;Facebook在这一进程中扮演了重要角色。本文将分析Facebook如何影响人际关系&#xff0c;包括沟通方式的转变、情感连接的变化以及社交互动的质量。 1. 沟通…

无极低码课程【redis windows下服务注册密码修改】

下载Windows版本的Redis linux环境 (自行下载) 1.打开官网https://redis.io/downloads/ windows环境 1.打开github https://github.com/microsoftarchive/redis/releases 然后选择你喜欢的版本zip或msi下载 2.这里下载zip版,解压后后,打开安装目录 3.双击redis-server…

Xcode使用Instruments的dsym还原符号堆栈问题

文章目录 设置符号表的步骤参考资料 设置符号表的步骤 instruments 的 Settings 中&#xff0c;可以设置符号表的搜索路径 没有生效的话&#xff0c;继续看 File 里面的 Symbols - 出现弹窗后点击 Add Symbols - 然后再点击 Apply。 参考资料 https://xjkstar.github.i…

初级网络工程师之从入门到入狱(四)

本文是我在学习过程中记录学习的点点滴滴&#xff0c;目的是为了学完之后巩固一下顺便也和大家分享一下&#xff0c;日后忘记了也可以方便快速的复习。 网络工程师从入门到入狱 前言一、Wlan应用实战1.1、拓扑图详解1.2、LSW11.3、AC11.4、抓包1.5、Tunnel隧道模式解析1.6、AP、…

Flink 06 聚合操作入门学习,真不难

抛砖引玉 让你统计1小时内每种商品的销售额&#xff0c;用Flink 该怎么实现。 还是让你统计1小时内每种商品的销售额&#xff0c;但是要过滤掉退款的订单&#xff0c;用Flink 该怎么实现。 学了本文两个操作&#xff0c;不信你还不会。 AggregateFunction ❝ 通常用于对数据…

React国际化中英文切换实现

目录 概况 安装 文件结构 引入 使用 正常使用 传参使用 概况 react-intl-universal 是一个国际化库&#xff0c;专门为 React 应用提供多语言支持。与 React 原生的 react-intl 相比&#xff0c;react-intl-universal 支持从远程服务器加载语言包&#xff0c;动态切换语…

【Python】selenium遇到“InvalidArgumentException”的解决方法

在使用try……except 的时候捕获到这个错误&#xff1a; InvalidArgumentException: invalid argument (Session info: chrome112.0.5614.0) 这个错误代表的是&#xff0c;当传入的参数不符合期望时&#xff0c;就会抛出这个异常&#xff1a; InvalidArgumentException: invali…

【MySQL 保姆级教学】在Linux(CentoS 7)中安装MySQL(1)

目录 1. 卸载linux&#xff08;Centos7&#xff09; 中不要的环境2. 获取MySQL官方yum源2.1 获取yum源前先查看自己 linux&#xff08;Centos&#xff09;的版本2.2 获取官方yum源 3. 安装xftp和连接4. 开放连接端口5. 上传文件到Centos76. 安装MySQL6.1 顺利安装6.2 查询是否安…

QGraphics类型学习使用【Qt】【C++】

QGraphics类型学习使用 需求过程全部完整代码 首先已知&#xff0c;QGraphicsView&#xff0c;QGraphicsScene, QGraphicsItem&#xff0c;分别称为&#xff1a;视图&#xff0c;场景&#xff0c;图元&#xff0c;图表就是各种各样的元素&#xff0c;图片元素&#xff0c;线条元…

Unity Apple Vision Pro 开发:Metal 渲染模式开启透视遇到背景黑屏的解决方法

XR 开发者社区链接&#xff1a; SpatialXR社区&#xff1a;完整课程、项目下载、项目孵化宣发、答疑、投融资、专属圈子 以下步骤适用于 PolySpatial 2.0 及以上的版本。 我们可以在 Project Settings 中的 Apple visionOS 里将 App Mode 设为 Metal Rendering with Composit…

【C语言】分支结构switch

switch分支语句 多适用于明确表达式结果的情况&#xff0c;多个分支&#xff0c;用if过于繁琐。 case后跟具体的表达式值&#xff0c;break&#xff1b;跳出分支语句。 #include <stdio.h> #include <math.h> /* 功能&#xff1a;选择结构&#xff08;switch&…

Flink CDC同步mysql数据到doris

前置参考 flink快速安装&#xff1a;Flink入门-CSDN博客 doris快速安装&#xff1a;Apache Doris快速安装-CSDN博客 Flink CDC简介 Flink CDC 是一个基于流的数据集成工具&#xff0c;旨在为用户提供一套功能更加全面的编程接口&#xff08;API&#xff09;。 该工具使得用户能…

AI测试之 TestGPT

如今最火热的技术莫非OpenAI的ChatGPT莫属&#xff0c;AI技术也在很多方面得到广泛应用。今天我们要介绍的TestGPT就是一个软件测试领域中当红的应用。 TestGPT是什么&#xff1f; TestGPT是一家总部位于以色列特拉维夫的初创公司 CodiumAI Ltd.&#xff0c;发布的一款用于测…

hadoop集群搭建-克隆虚拟机,安装jdk,hadoop

2.2 hadoop运行环境的搭建 2.2.1 环境准备 1&#xff09;安装模板虚拟机&#xff0c;IP地址 192.168.10.100&#xff0c;主机名hadoop100&#xff0c;内存41GB&#xff0c;硬盘50GB 2&#xff09;虚拟机配置 首先测试虚拟机是否可以正常上网&#xff0c;测试方法ping www.b…

配置环境windows-IIS默认拒绝put,delete的解决方案

方法一&#xff1a; <system.webServer> </system.webServer> 方法二&#xff1a;移除网站“模块”中的"webdavmodule"

【芯智雲城】Boradcom(博通) 多领域技术解决方案介绍

Broadcom Inc. 是一家全球领先的技术企业&#xff0c;业务范围囊括多种半导体、企业用软件和安全解决方案的设计、开发和供应。Broadcom 的类别领先产品组合在许多重要的市场中发挥作用&#xff0c;其中包括云、数据中心、网络、带宽、无线技术、存储&#xff0c;以及工业和企业…

元数据 - iXML

在专业的音频和视频制作中&#xff0c;元数据的准确传递对于后期制作和编辑至关重要。iXML&#xff08;iXML Metadata&#xff09;是一种开放的、可扩展的元数据规范&#xff0c;旨在在录音设备和数字音频工作站&#xff08;DAW&#xff09;之间传递详细的录音信息。 一、什么是…

单目相机和双目相机定位

1、单目相机 1.1模型 单目相机成像模型为小孔成像&#xff0c;涉及的坐标系包括世界坐标系、相机坐标系、图像坐标系以及像素坐标系。坐标系之间的转换关系如下&#xff1a; 1.2参数求解 张正友相机标定方法、设定世界坐标系精确求解 2、双目相机 2.1、模型 一般双目立体视…

低代码策略量化平台更新|大模型agents生态的一些思考

原创内容第680篇&#xff0c;专注量化投资、个人成长与财富自由。 用户判断星球会员后&#xff0c;会获得10个积分&#xff1a; 当其他用户发布策略&#xff0c;设置为下载需要积分时&#xff1a; 下载策略会扣除相应的积分&#xff0c;扣除的积分属于策略所有者。 策略运行结…

大型企业软件开发是什么样子的? - Web Dev Cody

引用自大型企业软件开发是什么样子的&#xff1f; - Web Dev Cody_哔哩哔哩_bilibili 一般来说 学技术的时候 我们会关注 开发语言特性 &#xff0c;各种高级语法糖&#xff0c;底层技术 但是很少有关注到企业里面的开发流程&#xff0c;本着以终为始&#xff08;以就业为导向…