21、系统定制:SystemUI 定制,StatusBar 与 NavigationBar 的车载适配

各位好,今天我们来聊聊车载系统里一个绕不开的话题——SystemUI 定制。

说实话,做手机 SystemUI 和做车载 SystemUI,完全是两码事。手机上的状态栏和导航栏,说白了就是给用户看时间、信号、电量,再加三个虚拟按键。但到了车上,这套逻辑基本要推倒重来。

我最早接触车载 SystemUI 时,心里还想着「不就是改改布局嘛」。结果一上手才发现,坑比想象的多得多。今天我就把我在项目中踩过的坑、总结的经验,一次性讲清楚。

为什么车载 SystemUI 不能直接用手机那套?

你想想看,手机是拿在手里的,屏幕小,交互靠触摸。车机呢?屏幕大,有的还是横屏,交互方式可能是触摸、旋钮、语音,甚至方向盘按键。

更关键的是——安全。驾驶员在开车时,视线离开前方超过 2 秒,风险就急剧上升。所以车载 UI 的设计原则第一条就是:减少视觉干扰,增大触控区域,信息一目了然

核心差异点:

  • 手机 StatusBar 显示通知、时间、信号;车载需要显示空调温度、驾驶模式、车辆状态
  • 手机 NavigationBar 是返回、主页、多任务;车载需要显示快捷控制、座椅加热、音量调节
  • 手机是竖屏为主;车机几乎全是横屏,且分辨率五花八门
  • 手机交互以触摸为主;车机还要兼容物理按键和旋钮

StatusBar 的车载适配:从信息展示到车辆控制

在 Android Automotive OS 里,StatusBar 不再只是「状态展示区」。它更像一个「信息聚合中心」。

我参与的那个项目,客户要求 StatusBar 左侧显示时间、室外温度、驾驶模式(经济/运动/舒适),右侧显示蓝牙连接状态、Wi-Fi 信号、电量。中间还要留出一块区域给「车辆警告信息」——比如胎压异常、车门未关。

嗯,这里要注意:车载 StatusBar 的高度通常比手机大。手机一般是 24dp 到 32dp,车机我建议至少 48dp 起步。为什么?因为驾驶员在行驶中很难精确点击小图标,触控区域越大越安全。

// 在 SystemUI 中调整 StatusBar 高度
// 文件路径: packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    // 车载定制:增大 StatusBar 高度
    ViewGroup.LayoutParams lp = getLayoutParams();
    lp.height = getResources().getDimensionPixelSize(R.dimen.status_bar_height_car);
    setLayoutParams(lp);
}

我的经验:不要硬编码高度值。不同车型的屏幕尺寸差异很大,建议在 dimens.xml 中定义多个版本,通过配置 overlay 来适配。

NavigationBar 的车载适配:从虚拟按键到快捷控制中心

手机上的 NavigationBar 就三个键:返回、主页、多任务。车载上呢?我见过最夸张的客户要求放了 7 个按钮:主页、返回、音量加、音量减、空调开关、座椅加热、驾驶模式切换。

这显然不合理。按钮太多,驾驶员根本记不住位置,操作时还要低头看,非常危险。

我当时的做法是:把 NavigationBar 分成两层。底层是固定的三个核心按钮(主页、返回、最近应用),上层是「可配置的快捷面板」,用户可以在设置里自定义显示哪些快捷开关。

// 车载 NavigationBar 布局示例
// 文件路径: packages/SystemUI/res/layout/navigation_bar_car.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center_vertical">

    <!-- 核心导航按钮 -->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center">
        <Button
            android:id="@+id/back_button"
            style="@style/CarNavButton"
            android:contentDescription="返回" />
        <Button
            android:id="@+id/home_button"
            style="@style/CarNavButton"
            android:contentDescription="主页" />
        <Button
            android:id="@+id/recent_button"
            style="@style/CarNavButton"
            android:contentDescription="最近应用" />
    </LinearLayout>

    <!-- 快捷控制区 -->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center">
        <!-- 动态添加的快捷按钮 -->
    </LinearLayout>
</LinearLayout>

避坑指南:我曾经在 NavigationBar 里直接用了手机上的 KeyButtonView,结果发现车载上点击响应区域太小,驾驶员经常误触。后来我改用 FrameLayout 包裹,把点击区域扩大到 64dp x 64dp,问题才解决。

车载 SystemUI 的核心架构图

下面这张图是我根据实际项目经验总结的,展示了车载 SystemUI 的整体架构和各模块的关系。

车载 SystemUI 核心架构 SystemUI 入口 StatusBar 模块 NavigationBar 模块 快捷面板模块 时间/温度/驾驶模式 车辆警告/状态图标 核心导航按钮 快捷控制按钮 底层服务:CarService / Vehicle HAL / 系统服务 硬件层:屏幕 / 触摸 / 旋钮 / 方向盘按键 入口 核心模块 子组件

实际项目中的定制要点

我在做车载 SystemUI 定制时,总结了几个关键点,分享给大家:

  1. 布局文件要独立:不要直接修改手机的布局文件。在 packages/SystemUI/res-car/ 下创建车载专用的布局,通过 overlay 机制加载。
  2. 交互方式要兼容:除了触摸,还要支持物理按键和旋钮。我建议在 KeyEvent 分发时,增加对方向盘按键的映射。
  3. 性能优化不能忘:车载屏幕分辨率高,SystemUI 的渲染压力大。我遇到过掉帧问题,后来通过减少过度绘制、使用硬件加速解决了。
  4. 多用户场景要考虑:车机可能有驾驶员和乘客两个用户,StatusBar 显示的内容要区分权限。

一个小技巧:调试车载 SystemUI 时,可以用 adb shell dumpsys activity service com.android.systemui/.SystemUIService 查看当前状态栏和导航栏的配置信息,非常方便。

总结

车载 SystemUI 的定制,核心就一句话:从手机思维切换到车载思维。不要想着把手机那套搬过来,而是要思考驾驶员在行驶中真正需要什么。

StatusBar 要突出车辆状态信息,NavigationBar 要简化操作路径。布局要大、信息要精、交互要稳。

嗯,今天的内容就到这里。如果你在实际项目中遇到什么问题,欢迎随时交流。


公众号:蓝海资料掘金营,微信 deep3321