车载 UI 框架:Car UI 库介绍、主题与样式定制、安全驾驶模式

好,我们进入车载 UI 框架这一章。说实话,做车载应用开发,UI 这块跟手机差别挺大的。手机你随便写个 RecyclerView 就能用,但在车上,你得考虑驾驶安全、屏幕尺寸、交互方式……嗯,Google 专门搞了一套 Car UI 库,就是为了解决这些问题。

Car UI 库是什么?

Car UI 库,全称是 androidx.car.appandroidx.car.ui。它不是一个普通的 UI 组件集合,而是专门为车载场景设计的。我个人的理解是,它把「安全」和「易用」这两个核心诉求,直接固化到了组件里。

举个例子,你写一个列表,手机版可能用 RecyclerView,但在车上,Car UI 库提供了 CarRecyclerView。它有什么特别?它会自动检测驾驶状态,如果车辆在行驶中,列表的点击区域会变大,滑动速度会变慢,甚至某些操作会被禁用。说白了,就是帮你做「分心优化」。

核心组件一览:
  • CarRecyclerView:安全优化的列表控件
  • CarButton:大尺寸、高对比度的按钮
  • CarToolbar:支持驾驶模式切换的工具栏
  • CarNavigationView:侧边导航,自动适配安全区域
  • CarAlertDialog:驾驶中只显示关键信息的弹窗

我记得第一次用 CarRecyclerView 时,还纳闷为什么它默认的点击区域那么大。后来看了源码才明白,它内部做了 TouchDelegate 的扩展,把触摸热区扩大了 1.5 倍。嗯,这就是细节。

主题与样式定制

车载 UI 的主题定制,跟手机不太一样。手机你可以搞各种花哨的渐变、阴影,但在车上,高对比度、大字体、清晰的信息层级才是王道。

Car UI 库提供了 CarThemeCarStyle 两个核心类。你可以在 res/values/themes.xml 里这样配置:

<style name="Theme.MyCarApp" parent="Theme.CarUI">
    <item name="carColorPrimary">@color/car_blue</item>
    <item name="carColorOnPrimary">@color/white</item>
    <item name="carFontFamily">@font/roboto_condensed</item>
    <item name="carTextSizeLarge">24sp</item>
    <item name="carTextSizeMedium">18sp</item>
    <item name="carTextSizeSmall">14sp</item>
</style>

这里要注意,carColorPrimary 不是随便选的。我在项目中遇到过一个问题:某个 OEM 要求主色调必须是深蓝色,但深蓝色在强光下几乎看不清。后来我们加了一个 carColorOnPrimary 的高亮色,才解决了可读性问题。

我的经验: 车载主题的对比度至少要到 4.5:1(WCAG AA 标准)。你可以用 ColorUtils.calculateContrast() 来验证。别问我怎么知道的——有一次测试反馈说「白天看不清按钮」,我连夜改的。

安全驾驶模式(Distraction Optimization)

这是车载 UI 最核心的部分,也是 Car UI 库存在的意义。安全驾驶模式,说白了就是「车辆行驶时,限制某些 UI 操作」。为什么?你想想看,司机在高速上开车,哪有精力去点一个 10px 的小按钮?

Car UI 库通过 CarContext 来获取驾驶状态。代码很简单:

// 在 Activity 或 Fragment 中
CarContext carContext = CarContext.create(this);
int drivingState = carContext.getDrivingState();

if (drivingState == CarDrivingStateEvent.DRIVING_STATE_MOVING) {
    // 车辆在行驶中,限制复杂操作
    disableComplexUI();
} else {
    // 停车或驻车,可以展示完整 UI
    enableFullUI();
}

但这里有个坑。我曾经以为只要判断 DRIVING_STATE_MOVING 就够了,结果发现有些车在等红绿灯时,状态还是 MOVING。嗯,后来我加了一个速度阈值判断:

if (drivingState == CarDrivingStateEvent.DRIVING_STATE_MOVING 
    && speedKmh > 5) {
    // 真正在行驶中
    applyDistractionOptimization();
}
注意: 不要完全依赖 Car UI 库的默认行为。不同 OEM 对「安全驾驶」的定义不同。有的要求车速超过 10km/h 就限制,有的要求 20km/h。最好在车辆配置中读取 OEM 的定制参数。

Distraction Optimization 的具体实现

Car UI 库提供了几个现成的优化策略:

  • 点击区域放大:所有可点击元素的最小触摸区域为 48dp x 48dp
  • 列表项简化:行驶中只显示标题和图标,隐藏详情
  • 动画禁用:减少滚动、切换时的动画效果,避免视觉干扰
  • 输入法限制:行驶中禁止弹出软键盘,除非是紧急输入

你可以通过 DistractionOptimizationManager 来注册自己的优化规则:

DistractionOptimizationManager manager = 
    new DistractionOptimizationManager(carContext);

manager.registerRule(new DistractionRule() {
    @Override
    public boolean shouldOptimize(View view, int drivingState) {
        // 自定义规则:如果视图是 EditText,且车辆在行驶中,则优化
        return view instanceof EditText 
            && drivingState == DRIVING_STATE_MOVING;
    }

    @Override
    public void applyOptimization(View view) {
        // 把 EditText 变成只读
        ((EditText) view).setEnabled(false);
        ((EditText) view).setFocusable(false);
    }
});

我个人习惯把优化规则写在单独的类里,方便测试和复用。你想想看,如果每个页面都写一遍,后期维护起来多痛苦。

知识体系结构图

下面这张图,是我梳理的本章知识脉络。你可以看到,Car UI 库、主题定制、安全驾驶模式这三者是如何关联的。

车载 UI 框架 Car UI 库 主题与样式定制 安全驾驶模式 CarRecyclerView CarButton CarToolbar CarAlertDialog carColorPrimary carFontFamily carTextSize 对比度检查 DrivingState 速度阈值 点击区域放大 输入法限制 三者协同:Car UI 库提供组件,主题定制外观,安全模式控制行为

避坑指南

最后,分享几个我踩过的坑:

  • 不要直接继承 Theme.MaterialComponents:车载主题必须继承 Theme.CarUI,否则 Car UI 库的组件会渲染异常。我曾经因为这个,浪费了两天排查。
  • 安全驾驶模式的测试:模拟器里很难模拟真实的驾驶状态。我建议用 adb shell dumpsys car_service 来手动注入驾驶事件,比 UI 操作靠谱。
  • 主题定制要跟 OEM 对齐:不同车厂对字体、颜色、间距的要求都不一样。最好在项目初期就拿到 OEM 的设计规范,否则后期改起来很痛苦。

嗯,这一章的内容就到这里。车载 UI 框架的核心就是「安全第一」,所有的组件、主题、优化策略,都是围绕这个目标展开的。你只要记住这一点,写出来的代码就不会跑偏。

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