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 定制时,总结了几个关键点,分享给大家:
- 布局文件要独立:不要直接修改手机的布局文件。在
packages/SystemUI/res-car/下创建车载专用的布局,通过 overlay 机制加载。 - 交互方式要兼容:除了触摸,还要支持物理按键和旋钮。我建议在
KeyEvent分发时,增加对方向盘按键的映射。 - 性能优化不能忘:车载屏幕分辨率高,SystemUI 的渲染压力大。我遇到过掉帧问题,后来通过减少过度绘制、使用硬件加速解决了。
- 多用户场景要考虑:车机可能有驾驶员和乘客两个用户,StatusBar 显示的内容要区分权限。
一个小技巧:调试车载 SystemUI 时,可以用 adb shell dumpsys activity service com.android.systemui/.SystemUIService 查看当前状态栏和导航栏的配置信息,非常方便。
总结
车载 SystemUI 的定制,核心就一句话:从手机思维切换到车载思维。不要想着把手机那套搬过来,而是要思考驾驶员在行驶中真正需要什么。
StatusBar 要突出车辆状态信息,NavigationBar 要简化操作路径。布局要大、信息要精、交互要稳。
嗯,今天的内容就到这里。如果你在实际项目中遇到什么问题,欢迎随时交流。
公众号:蓝海资料掘金营,微信 deep3321