android 13 Launcher中应用列表数量,大小如何控制的?

目录

一.背景

二.分析


一.背景

由于需要定制Launcher UI,其中应用列表数量和设备匹配度是一个不好把握的度,有时候这个设备应用列表匹配上了,另一个设备可能就匹配错误了,所以今天我们讲一下如何将当前设置的应用列表的行数、列数精确匹配到当前设备上,并且做到不影响或者说尽可能小的影响其他设备应用列表显示

二.分析

首先应用列表匹配文件在launcher中的device_profiles.xml中,这里默认有匹配各种屏幕的应用列表参数,首先我们分析下默认的device_profiles.xml里面的内容,如下是添加注释的删减版本

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<!-- 
    Profiles 根节点:包含多种网格配置方案。
    每一种 grid-option 代表一种用户可选或系统预设的布局(如 4x4, 5x5)。
-->
<profiles xmlns:launcher="http://schemas.android.com/apk/res-auto" >

    <!-- 
        grid-option: 定义一个逻辑网格方案
        name: 内部识别名称
        numRows/numColumns: 桌面主屏幕的行数和列数
        numFolderRows/numFolderColumns: 文件夹内部的行数和列数
        numHotseatIcons: 底部快捷栏(Hotseat)的图标数量
        dbFile: 该网格关联的数据库文件名(不同网格存不同的位置,防止切换时图标乱掉)
        defaultLayoutId: 首次开机时默认加载的桌面图标布局(定义在 res/xml/ 下)
        deviceCategory: 设备类别,用于初筛(phone-手机, tablet-平板, multi_display-折叠屏/多屏)
    -->
    <grid-option
        launcher:name="4_by_4"
        launcher:numRows="4"
        launcher:numColumns="4"
        launcher:numFolderRows="3"
        launcher:numFolderColumns="4"
        launcher:numHotseatIcons="4"
        launcher:numExtendedHotseatIcons="6"
        launcher:dbFile="launcher_4_by_4.db"
        launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_split"
        launcher:defaultLayoutId="@xml/default_workspace_4x4"
        launcher:deviceCategory="phone|multi_display" >

        <!-- 
            display-option: 针对具体屏幕参数的微调方案
            name: 方案描述(如 Nexus 4, Stubby 等)
            minWidthDps / minHeightDps: 匹配触发的最小宽度/高度(单位 dp)。这是匹配的核心!
            iconImageSize: 桌面图标图片的尺寸 (dp)
            iconTextSize: 图标下方文字的大小 (sp)
            allAppsBorderSpace: "所有应用"列表中的图标间距
            allAppsCellHeight: "所有应用"列表中每个格子的高度
            canBeDefault: 是否可以作为该设备的默认匹配项
        -->
        <display-option
            launcher:name="Nexus 4"
            launcher:minWidthDps="359"
            launcher:minHeightDps="567"
            launcher:iconImageSize="54"
            launcher:iconTextSize="13.0"
            launcher:allAppsBorderSpace="16"
            launcher:allAppsCellHeight="104"
            launcher:canBeDefault="true" />

        <!-- 更多 display-option... 系统会选择最接近当前屏幕尺寸的一个 -->
    </grid-option>

    <!-- 
        tablet 专属配置方案(6x5 网格)
        isScalable: 是否开启缩放支持(通常平板需要动态调整)
        devicePaddingId: 引用特定的间距配置(定义在 paddings.xml 中)
    -->
    <grid-option
        launcher:name="6_by_5"
        launcher:numRows="5"
        launcher:numColumns="6"
        launcher:deviceCategory="tablet" >

        <display-option
            launcher:name="Tablet"
            launcher:minWidthDps="900"
            launcher:minHeightDps="820"
            launcher:iconImageSize="60"
            <!-- 针对平板特有的间距微调 -->
            launcher:borderSpaceHorizontal="16"
            launcher:borderSpaceVertical="64"
            launcher:horizontalMargin="54"
            launcher:hotseatBarBottomSpace="76"
            launcher:canBeDefault="true" />
    </grid-option>

</profiles>

Launcher3 在启动时,会通过 InvariantDeviceProfile.java 类来解析这个 XML。匹配过程遵循 "由大到小,最接近匹配" 的原则:

    1. 设备类别过滤 (deviceCategory)

      • 系统首先获取当前设备的类型(Phone, Tablet 或 Two-panel 折叠屏)。
      • 只有符合 deviceCategorygrid-option 会被列入候选名单。
    2. 屏幕尺寸匹配 (minWidthDps / minHeightDps)

      • 系统测量当前屏幕的实际可用 DP 值(考虑旋转后的短边和长边)。
      • 核心逻辑 :系统会遍历该 grid-option 下所有的 display-option,寻找 minWidthDpsminHeightDps小于或等于当前实际屏幕尺寸的项。
      • 如果有多个符合条件的项,系统会选择 最接近(最适配) 实际尺寸的那一个。

然后比如我们当前设备如何匹配上的,需要看下屏幕尺寸,注意这里的尺寸是dp位单位的,所以我们要得到设备的分辨率以及屏幕密度进行计算,这两个参数用adb都能获取到

分辨率:adb shell wm size

屏幕密度:adb shell wm density

计算dp值方式

3. 计算 dp 值

密度比例 factor = dpi / 160

屏幕宽度 dp = 宽度像素 / factor

示例计算:factor = 440 / 160 = 2.75

屏幕宽度 dp = 1080 / 2.75 ≈ 392 dp

屏幕高度 dp = 2340 / 2.75 ≈ 850 dp

所以我们当前设备的dp值是:360x720

所以匹配的就是minWidthDps小于360并且minHeightDps小于720,如果多个符合条件则找最接近的那个,如下是我添加的适配当前设备的option

可以看出来这样就可以精确匹配到当前设备了,当然除了宽高还有别的属性可以进行匹配吗?当然是有的,inlineQsb这个属性也可以进行区分,看一下这个属性需要设置哪些值

XML 复制代码
    <!-- 默认全部关闭 -->
    <attr name="inlineQsb" format="integer">
        <!-- 仅在竖屏启用(值=1) -->
        <flag name="portrait" value="1" />
        <!-- 仅在横屏启用(值=2) -->
        <flag name="landscape" value="2" />
        <!-- 仅在双面板竖屏启用(值=4) -->
        <flag name="twoPanelPortrait" value="4" />
        <!-- 仅在双面板横屏启用(值=8) -->
        <flag name="twoPanelLandscape" value="8" />
    </attr>

所以我们要匹配竖屏的直接设置2,横屏的设置1,这样可以更加精确些,还有许多其他属性,但是我没有使用,不知道是否有用,具体代码如下:

XML 复制代码
<declare-styleable name="GridDisplayOption">
    <!-- 网格配置的名称,用于标识不同的配置方案 -->
    <attr name="name" format="string" />

    <!-- 基本网格布局参数 -->
    <attr name="numRows" format="integer" />         <!-- 网格行数 -->
    <attr name="numColumns" format="integer" />      <!-- 网格列数 -->
    <!-- 搜索容器列数,默认等于 numColumns -->
    <attr name="numSearchContainerColumns" format="integer" />

    <!-- 单元格样式参考,默认使用 CellStyleDefault -->
    <attr name="cellStyle" format="reference" />

    <!-- 文件夹网格参数,默认使用主网格参数 -->
    <attr name="numFolderRows" format="integer" />    <!-- 文件夹行数 -->
    <attr name="numFolderColumns" format="integer" /> <!-- 文件夹列数 -->
    <attr name="folderStyle" format="reference" />    <!-- 文件夹样式参考 -->

    <!-- 所有应用(应用抽屉)样式,默认使用 AllAppsStyleDefault -->
    <attr name="allAppsStyle" format="reference" />

    <!-- 所有应用(应用抽屉)网格参数 -->
    <attr name="numAllAppsColumns" format="integer" />          <!-- 所有应用列数 -->
    <!-- 扩展所有应用的列数,默认 2 * numAllAppsColumns -->
    <attr name="numExtendedAllAppsColumns" format="integer" />

    <!-- 底部热座(Dock栏)参数 -->
    <attr name="numHotseatIcons" format="integer" />           <!-- 热座图标数量 -->
    <!-- 扩展热座图标数量,默认 2 * numHotseatIcons -->
    <attr name="numExtendedHotseatIcons" format="integer" />

    <!-- 热座在不同布局中的列跨度配置 -->
    <!-- 默认全部等于 numColumns -->
    <attr name="hotseatColumnSpan" format="integer" />               <!-- 普通模式 -->
    <attr name="hotseatColumnSpanLandscape" format="integer" />      <!-- 横屏模式 -->
    <attr name="hotseatColumnSpanTwoPanelLandscape" format="integer" /><!-- 双面板横屏 -->
    <attr name="hotseatColumnSpanTwoPanelPortrait" format="integer" /> <!-- 双面板竖屏 -->

    <!-- 大屏三键导航按钮的结束间距 -->
    <!-- 默认 @dimen/taskbar_button_margin_default -->
    <attr name="inlineNavButtonsEndSpacing" format="reference" />

    <!-- 数据库和布局相关 -->
    <attr name="dbFile" format="string" />           <!-- 数据库文件名 -->
    <attr name="defaultLayoutId" format="reference" /> <!-- 默认布局ID -->
    <attr name="demoModeLayoutId" format="reference" /> <!-- 演示模式布局ID -->
    <attr name="isScalable" format="boolean" />       <!-- 是否支持缩放 -->
    <attr name="devicePaddingId" format="reference" /> <!-- 设备内边距ID -->

    <!-- 设备类别标志位,用于指定此配置适用的设备类型 -->
    <!-- 默认所有类别都启用(phone|tablet|multi_display) -->
    <attr name="deviceCategory" format="integer">
        <!-- 手机设备(值=1) -->
        <flag name="phone" value="1" />
        <!-- 平板设备(值=2) -->
        <flag name="tablet" value="2" />
        <!-- 多显示设备(值=4) -->
        <flag name="multi_display" value="4" />
    </attr>

    <!-- 内联搜索框(Quick Search Box)启用标志位 -->
    <!-- 默认全部关闭 -->
    <attr name="inlineQsb" format="integer">
        <!-- 仅在竖屏启用(值=1) -->
        <flag name="portrait" value="1" />
        <!-- 仅在横屏启用(值=2) -->
        <flag name="landscape" value="2" />
        <!-- 仅在双面板竖屏启用(值=4) -->
        <flag name="twoPanelPortrait" value="4" />
        <!-- 仅在双面板横屏启用(值=8) -->
        <flag name="twoPanelLandscape" value="8" />
    </attr>
</declare-styleable>
XML 复制代码
<declare-styleable name="ProfileDisplayOption">
    <!-- 基础匹配属性 -->
    <attr name="name" /> <!-- 该布局方案的显示名称(如:Large Phone) -->
    <attr name="minWidthDps" format="float" /> <!-- 触发该方案所需的设备最小宽度 (dp) -->
    <attr name="minHeightDps" format="float" /> <!-- 触发该方案所需的设备最小高度 (dp) -->

    <!-- 桌面网格格子大小 (仅在 GridDisplayOption 的 isScalable 为 true 时生效) -->
    <attr name="minCellHeight" format="float" /> <!-- 竖屏下单元格的最小高度 -->
    <attr name="minCellWidth" format="float" /> <!-- 竖屏下单元格的最小宽度 -->
    <attr name="minCellHeightLandscape" format="float" /> <!-- 横屏下单元格高度,未指定则取 minCellHeight -->
    <attr name="minCellWidthLandscape" format="float" /> <!-- 横屏下单元格宽度,未指定则取 minCellWidth -->
    
    <!-- 双面板/折叠屏下的网格大小 -->
    <attr name="minCellHeightTwoPanelPortrait" format="float" /> <!-- 双面板竖屏高度 -->
    <attr name="minCellWidthTwoPanelPortrait" format="float" /> <!-- 双面板竖屏宽度 -->
    <attr name="minCellHeightTwoPanelLandscape" format="float" /> <!-- 双面板横屏高度 -->
    <attr name="minCellWidthTwoPanelLandscape" format="float" /> <!-- 双面板横屏宽度 -->

    <!-- 单元格之间的间距 (Border Space) -->
    <!-- 仅在 isScalable 为 true 时使用 -->
    <attr name="borderSpace" format="float" /> <!-- 统一的行列间距 -->
    <attr name="borderSpaceHorizontal" format="float" /> <!-- 横向间距(格子右侧),默认取 borderSpace -->
    <attr name="borderSpaceVertical" format="float" /> <!-- 纵向间距(格子下方),默认取 borderSpace -->
    
    <!-- 横屏下的间距配置 -->
    <attr name="borderSpaceLandscape" format="float" /> <!-- 横屏统一间距,默认取 borderSpace -->
    <attr name="borderSpaceLandscapeHorizontal" format="float" /> <!-- 横屏横向间距 -->
    <attr name="borderSpaceLandscapeVertical" format="float" /> <!-- 横屏纵向间距 -->
    
    <!-- 双面板/折叠屏下的间距配置 -->
    <attr name="borderSpaceTwoPanelPortrait" format="float" /> <!-- 双屏竖屏统一间距 -->
    <attr name="borderSpaceTwoPanelPortraitHorizontal" format="float" /> <!-- 双屏竖屏横向 -->
    <attr name="borderSpaceTwoPanelPortraitVertical" format="float" /> <!-- 双屏竖屏纵向 -->
    <attr name="borderSpaceTwoPanelLandscape" format="float" /> <!-- 双屏横屏统一间距 -->
    <attr name="borderSpaceTwoPanelLandscapeHorizontal" format="float" /> <!-- 双屏横屏横向 -->
    <attr name="borderSpaceTwoPanelLandscapeVertical" format="float" /> <!-- 双屏横屏纵向 -->

    <!-- "所有应用"列表(抽屉)的单元格配置 -->
    <!-- 如果 isScalable 为 true,默认取 minCellHeight;如果为 false,则必须定义 -->
    <attr name="allAppsCellHeight" format="float" /> 
    <attr name="allAppsCellWidth" format="float" /> <!-- 默认取 minCellWidth -->
    <attr name="allAppsCellHeightLandscape" format="float" /> <!-- 抽屉横屏格子高 -->
    <attr name="allAppsCellWidthLandscape" format="float" /> <!-- 抽屉横屏格子宽 -->
    <attr name="allAppsCellHeightTwoPanelPortrait" format="float" /> <!-- 双屏竖屏抽屉格子高 -->
    <attr name="allAppsCellWidthTwoPanelPortrait" format="float" />
    <attr name="allAppsCellHeightTwoPanelLandscape" format="float" /> <!-- 双屏横屏抽屉格子高 -->
    <attr name="allAppsCellWidthTwoPanelLandscape" format="float" />

    <!-- 抽屉内的图标及文字大小 -->
    <attr name="allAppsIconSize" format="float" /> <!-- 默认取 iconImageSize -->
    <attr name="allAppsIconSizeLandscape" format="float" /> 
    <attr name="allAppsIconSizeTwoPanelPortrait" format="float" />
    <attr name="allAppsIconSizeTwoPanelLandscape" format="float" />
    <attr name="allAppsIconTextSize" format="float" /> <!-- 默认取 iconTextSize -->
    <attr name="allAppsIconTextSizeTwoPanelPortrait" format="float" />
    <attr name="allAppsIconTextSizeTwoPanelLandscape" format="float" />

    <!-- 抽屉内的间距配置(逻辑同上,可独立控制抽屉内的图标疏密程度) -->
    <attr name="allAppsBorderSpace" format="float" /> <!-- 默认取 borderSpace -->
    <attr name="allAppsBorderSpaceHorizontal" format="float" />
    <attr name="allAppsBorderSpaceVertical" format="float" />
    <attr name="allAppsBorderSpaceLandscape" format="float" />
    <attr name="allAppsBorderSpaceLandscapeHorizontal" format="float" />
    <attr name="allAppsBorderSpaceLandscapeVertical" format="float" />
    <attr name="allAppsBorderSpaceTwoPanelPortrait" format="float" />
    <attr name="allAppsBorderSpaceTwoPanelPortraitHorizontal" format="float" />
    <attr name="allAppsBorderSpaceTwoPanelPortraitVertical" format="float" />
    <attr name="allAppsBorderSpaceTwoPanelLandscape" format="float" />
    <attr name="allAppsBorderSpaceTwoPanelLandscapeHorizontal" format="float" />
    <attr name="allAppsBorderSpaceTwoPanelLandscapeVertical" format="float" />

    <!-- 热搜栏(Hotseat/Dock栏)及 搜索框(QSB)空间配置 -->
    <attr name="hotseatBarBottomSpace" format="float" /> <!-- Dock栏距离屏幕底部的间距 -->
    <attr name="hotseatBarBottomSpaceLandscape" format="float" />
    <attr name="hotseatBarBottomSpaceTwoPanelLandscape" format="float" />
    <attr name="hotseatBarBottomSpaceTwoPanelPortrait" format="float" />

    <attr name="hotseatQsbSpace" format="float" /> <!-- Hotseat与搜索框之间的间距 -->
    <attr name="hotseatQsbSpaceLandscape" format="float" />
    <attr name="hotseatQsbSpaceTwoPanelLandscape" format="float" />
    <attr name="hotseatQsbSpaceTwoPanelPortrait" format="float" />

    <!-- Android 13 任务栏(Taskbar)配置 -->
    <attr name="transientTaskbarIconSize" format="float" /> <!-- 悬浮任务栏图标大小 -->
    <attr name="transientTaskbarIconSizeLandscape" format="float" />
    <attr name="transientTaskbarIconSizeTwoPanelLandscape" format="float" />
    <attr name="transientTaskbarIconSizeTwoPanelPortrait" format="float" />

    <!-- 桌面主屏幕图标及文字大小 -->
    <attr name="iconImageSize" format="float" /> <!-- 竖屏图标大小 -->
    <attr name="iconSizeLandscape" format="float" /> <!-- 横屏图标大小,默认取 iconImageSize -->
    <attr name="iconSizeTwoPanelPortrait" format="float" /> <!-- 双屏竖屏图标大小 -->
    <attr name="iconSizeTwoPanelLandscape" format="float" /> <!-- 双屏横屏图标大小 -->

    <attr name="iconTextSize" format="float" /> <!-- 竖屏文字大小 -->
    <attr name="iconTextSizeLandscape" format="float" />
    <attr name="iconTextSizeTwoPanelPortrait" format="float" />
    <attr name="iconTextSizeTwoPanelLandscape" format="float" />

    <!-- 任务栏对齐属性(主要用于大屏/平板的三键导航模式) -->
    <attr name="startAlignTaskbar" format="boolean" /> <!-- 任务栏是否靠左对齐,默认 false(居中) -->
    <attr name="startAlignTaskbarLandscape" format="boolean" />
    <attr name="startAlignTaskbarTwoPanelLandscape" format="boolean" />
    <attr name="startAlignTaskbarTwoPanelPortrait" format="boolean" />

    <!-- 默认配置项标记 -->
    <attr name="canBeDefault" format="boolean" /> <!-- 如果设置,该选项将被用作确定默认网格的基准 -->

    <!-- 工作区(Workspace)页边距 -->
    <attr name="horizontalMargin" format="float"/> <!-- 工作区左右两边的留白间距 (仅 isScalable 为 true 时使用) -->
    <attr name="horizontalMarginLandscape" format="float"/>
    <attr name="horizontalMarginTwoPanelLandscape" format="float"/>
    <attr name="horizontalMarginTwoPanelPortrait" format="float"/>

</declare-styleable>
相关推荐
决胜万里3 小时前
zephyr上实现Android Fence机制
android·嵌入式
程序员陆业聪12 小时前
2025 年客户端技术盘点与 2026 年技术展望
android
xhBruce13 小时前
Android USB 存储 冷启动(开机自动插着 U 盘)场景
android·usb·vold
CheungChunChiu13 小时前
在 Android 14 上使用 scrcpy 的投屏问题与解决方案
android·adb
xhBruce14 小时前
Android屏幕旋转DisplayRotation - Android15
android·dms
alexhilton14 小时前
使用LoRA微调Gemma实现移动端推理
android·kotlin·android jetpack
冬奇Lab14 小时前
Zygote进程孵化与应用启动机制:从fork到SystemServer的完整旅程
android·源码阅读
姜行运16 小时前
【Linux】基础指令2
android·linux·服务器
大模型玩家七七17 小时前
技术抉择:微调还是 RAG?——以春节祝福生成为例
android·java·大数据·开发语言·人工智能·算法·安全