自定义系统栏

如需自定义系统栏,请将 XML 配置和 Dagger 模块与界面组件结合使用。

定义系统栏行为

如需定义系统栏,请在 XML 文件中使用 <SystemBar> 标记来定义 外观和动画。此 XML 文件是运行时资源叠加层 (RRO) 的一部分。

SystemBar 标记属性

系统栏配置的根元素是 <SystemBar>,它支持 以下属性:

属性 状态 说明
id 必需 系统栏的唯一资源 ID。例如, @id/my_custom_status_bar
type 必需 指定系统栏的类型,可以是 statusnavigation
barZOrder 必需

表示系统栏 Z 顺序的整数。值越大 表示系统在其他栏之上绘制该栏。必须是正 整数。适用以下规则:

  • 如果您在浮动通知上方显示系统栏,则 此值必须大于 10
  • 重叠的系统栏不能具有相同的 Z 顺序
defaultVariant 必需 系统栏初始化时默认应用的 <Variant> 的 ID
displayId 可选 系统栏初始化时默认应用的 <Variant> 的 ID
hideForKeyboard 可选

布尔值 truefalse,用于指示在软件键盘处于活动状态时系统栏是否自动隐藏。此属性的默认值为 false

如果此属性为 true,您必须为系统栏提供 _System_Show_Panel_System_Hide_Panel 过渡。

dragOpenNotification 可选

布尔值 truefalse,用于指示 系统栏是否自动触发打开通知面板。 此属性的默认值为 false

dragCloseNotification 可选

布尔值 truefalse,用于指示 系统栏是否自动触发关闭通知面板。 此属性的默认值为 false

系统栏 ID 和类型

避免使用 TopCarSystemBarBottomCarSystemBarLeftCarSystemBarRightCarSystemBar 作为 id 值。系统保留这些 ID 以实现向后兼容性,使用这些 ID 可能会导致意外行为。

对于基本的顶部状态栏和底部导航栏配置,请分别使用 statusnav 作为 type 属性值。

如果您使用这些 ID,则可以跳过标题为 “使用 Dagger 提供系统栏界面”的部分。

<Variant>
定义视觉状态。如需了解详情,请参阅使用变体 设计视觉状态。在 <SystemBar> 标记中,定义一个或多个 <Variant> 标记。每个变体代表一个不同的视觉状态,并包含控制该状态下系统栏外观的属性。
<Visibility isVisible="true|false">
控制系统栏的可见性。isVisible 布尔值用于指示系统栏是否可见。
<Alpha alpha="float_value">
控制系统栏的透明度。alpha 的值介于 0.0(完全透明)和 1.0(完全不透明)之间。
<Bounds .../>

定义系统栏的位置和大小。对于 <SystemBar> 元素, 边界 必须 触及显示屏的至少一条边(左、上、 右或下)。属性包括:

  • lefttoprightbottom:绝对坐标。
  • widthheight:尺寸。
  • leftOffsettopOffsetrightOffsetbottomOffset:相对于矩形中心的偏移量。
<Corner radius="dimen"/>

定义系统栏的圆角半径。对于 radius,请输入圆角半径的尺寸。

<Insets .../>

定义系统栏的内边距。属性包括 lefttoprightbottom。对于每个属性,请输入内边距的尺寸值。

<Gravity .../>

定义系统栏内容的重心。如需了解详情,请参阅源代码中的 HunTagXmlParserKt.GRAVITY_TAG

  • 如果您省略了重心的值,系统会在内部计算该值。
  • 支持的值是 TOPBOTTOMLEFTRIGHTCENTERCENTER_HORIZONTALCENTER_VERTICALFILL_HORIZONTAL 的组合, 每个值之间用 | 字符分隔。

尺寸单位

使用 pxdp(或 dip)、% 或对 dimensionintegerfractionstringattribute 资源的引用来指定尺寸。

过渡:在变体之间添加动画效果

如需了解详情,请参阅配置转场。使用 <Transitions> 块定义系统栏在不同变体之间添加动画效果的方式:

推荐项 标记属性
<Transition> fromVarianttoVariantonEventonEventTokensanimatordurationdelayinterpolator
<Transitions> defaultDurationdefaultInterpolator

只有在为非沉浸式模式用例定义过渡时,可缩放界面才支持系统栏中的过渡。这意味着,当沉浸式模式隐藏(或显示)系统栏时,不会触发系统栏的可缩放界面窗口过渡。

可缩放界面会继续发送用于隐藏(或显示)系统栏的事件,以便其他面板可以根据需要做出响应,同时必须提供用于隐藏和显示系统栏的过渡,以确保 hideForKeyboard 属性正常运行。请考虑以下示例 XML 结构:

<SystemBar id="@id/my_custom_status_bar" type="status" barZOrder="0" defaultVariant="@id/default_variant" hideForKeyboard="true">
    <Variant id="@+id/default_variant">
        <Bounds top="0px" left="0px" right="100%" height="100px"/>
        <Visibility isVisible="true"/>
    </Variant>
    <Variant id="@+id/hidden_variant" parent="@id/default_variant">
        <Visibility isVisible="false"/>
    </Variant>
    <Transitions>
        <Transition onEvent="_System_Show_Panel" onEventTokens="panelId= my_custom_status_bar" toVariant="@id/default_variant"/>
        <Transition onEvent="_System_Hide_Panel" onEventTokens="panelId= my_custom_status_bar" toVariant="@id/hidden_variant"/>
    </Transitions>
</SystemBar>

使用 Dagger 提供系统栏界面

在 XML 中定义系统栏后,请提供实际的 ViewWindow。 为此,请将应用替换项应用于默认 Dagger 模块 CarSystemBarModule.java。例如:

import com.android.systemui.car.systembar.CarSystemBarViewSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplierUsingLayout;
import com.example.R;

import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;

@Module
public abstract class MySystemBarModule extends CarSystemBarModule {

    @Provides
    @IntoMap
    @StringKey("my_custom_status_bar") // Matches the <SystemBar> id
    static CarSystemBarViewSupplier bindMyCustomStatusBarViewSupplier() {
        return new CarSystemBarViewSupplierUsingLayout(
            R.layout.my_custom_status_bar, // provisioned layout
            R.layout.my_custom_status_bar_unprovisioned // unprovisioned layout
        );
    }

    @Provides
    @IntoMap
    @StringKey("my_custom_status_bar") // Matches the <SystemBar> id
    static CarSystemBarWindowSupplier bindMyCustomStatusBarWindowSupplier() {
        return new CarSystemBarWindowSupplierUsingLayout(
            R.layout.my_navigation_bar_window, // Can reuse existing window layouts
            R.id.my_custom_bar_window // The ID that will be assigned to the window
        );
    }
}

在 SystemUI 替换项中创建 Dagger 模块

如需扩充自定义布局资源,请使用 CarSystemBarViewSupplierUsingLayoutCarSystemBarWindowSupplierUsingLayout 类。

创建一个 Dagger 模块以提供自定义提供方。@StringKey 必须 与 id 在您的 <SystemBar> XML 标记中匹配。

如需替换 CarSystemBarModule,请参阅此代码示例:

import com.android.systemui.car.systembar.CarSystemBarViewSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplier;
import com.android.systemui.car.systembar.CarSystemBarWindowSupplierUsingLayout;
import com.example.R;

import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;

@Module
public abstract class MySystemBarModule extends CarSystemBarModule {

    @Provides
    @IntoMap
    @StringKey("my_custom_status_bar") // Matches the <SystemBar> id
    static CarSystemBarViewSupplier bindMyCustomStatusBarViewSupplier() {
        return new CarSystemBarViewSupplierUsingLayout(
            R.layout.my_custom_status_bar, // provisioned layout
            R.layout.my_custom_status_bar_unprovisioned // unprovisioned layout
        );
    }

    @Provides
    @IntoMap
    @StringKey("my_custom_status_bar") // Matches the <SystemBar> id
    static CarSystemBarWindowSupplier bindMyCustomStatusBarWindowSupplier() {
        return new CarSystemBarWindowSupplierUsingLayout(
            R.layout.my_navigation_bar_window, // Can reuse existing window layouts
            R.id.my_custom_bar_window // The ID that will be assigned to the window
        );
    }
}

使用 RRO 创建系统级配置

在 RRO 的 res/values/config.xml 文件中设置多个影响系统栏的系统级配置。

停用旧版系统栏

为防止与可缩放界面发生冲突,请将以下标志设置为 false,以停用旧版系统栏配置:

<resources>
    <bool name="config_enableTopSystemBar">false</bool>
    <bool name="config_enableBottomSystemBar">false</bool>
    <bool name="config_enableLeftSystemBar">false</bool>
    <bool name="config_enableRightSystemBar">false</bool>
</resources>

隐私指示标志位置

config_privacyIndicatorLocation 字符串资源用于指定哪个系统栏托管隐私指示标志。该值必须是 id<SystemBar> 名称。

<resources>
    <!-- "my_custom_status_bar" corresponds to the android:id name of a SystemBar -->
    <string name="config_privacyIndicatorLocation">my_custom_status_bar</string>
</resources>

拖动事件监听器

这些配置用于指定哪些系统栏监听拖动事件(例如,向下滑动以打开通知面板)。从搭载可缩放界面的 Android Automotive OS 开始,请使用 XML 属性作为默认值,而不是使用驱动发现资源数组来定义这些功能。

推荐:XML 驱动的发现(可缩放界面)

直接在叠加层 XML 中的 <SystemBar> 标记内使用 dragOpenNotificationdragCloseNotification 属性 :

<SystemBar id="@id/my_custom_status_bar" type="status" barZOrder="0" defaultVariant="@id/default_variant" dragOpenNotification="true">
    <Variant id="@+id/default_variant">
        <Bounds top="0px" left="0px" right="100%" height="100px"/>
        <Visibility isVisible="true"/>
    </Variant>
</SystemBar>

旧版:资源数组(回退)

如果您要维护非可缩放界面 build,或者需要为向后兼容的设备指定监听器,请在 RRO 的 res/values/config.xml 中使用旧版 string-array 方法。这些 string-array 资源用于指定哪些系统栏监听拖动事件。例如,打开通知面板。每个 <item> 都是系统栏的 id 名称。

  • config_registerHvacDragCloseListener
  • config_notificationDragOpenListener
  • config_notificationDragCloseListener

例如:

<resources>
    <string-array name="config_notificationDragOpenListener" translatable="false">
        <item>my_custom_status_bar</item>
    </string-array>
</resources>

构建和部署

如需构建和部署状态栏,请执行以下操作:

  1. 使用修改后的 SystemUI 替换应用刷写设备。

  2. 使用 Android 构建系统 (m) 编译 RRO 项目。

  3. 将生成的 RRO APK 部署到 Android Automotive 设备。使用 adb install 或刷写包含 RRO 的完整 build。