本节我们学习一个导航页功能,学习如何使用Flutter开发鸿蒙应用。

首先我们看一下项目目录:
在这里插入图片描述

接下来我们从基础层拆解,怎样一步步构建起来整个项目。

1. lib/models/TyrePsi.dart

定义了一个表示轮胎胎压数据的类 TyrePsi,并创建了一个包含四个轮胎数据的示例列表 demoPsiList。

这段代码通常用于 Flutter 或 Dart 应用中,用来展示车辆四个轮胎的实时状态(胎压值、温度、是否低压报警)。

类定义 (TyrePsi):
psi: 胎压值,单位为 psi(磅/平方英寸)。
temp: 轮胎温度,单位为摄氏度 (°C)。
isLowPressure: 布尔值,标记该轮胎是否处于低气压报警状态。

示例数据 (demoPsiList):
左前轮 (索引 0): 胎压 23.6 psi,温度 56°C,报警(数值明显低于其他轮胎,属于异常值)。
右前轮 (索引 1): 胎压 35.0 psi,温度 41°C,正常。
左后轮 (索引 2): 胎压 34.6 psi,温度 41°C,正常。
右后轮 (索引 3): 胎压 34.8 psi,温度 42°C,正常。

2. lib/home_controller.dart

定义了一个名为 HomeController 的类,该类继承自 ChangeNotifier。这段代码通常用于 Flutter 应用中,配合 Provider 状态管理库来管理应用的全局状态。

这段代码逻辑主要围绕一个汽车控制面板的 UI 状态进行管理,包括底部导航栏、车门锁状态、空调模式以及轮胎信息的显示控制。

A. 底部导航控制
selectedBottomTab: 记录当前选中的底部导航栏索引。
onBottomNavigationTabChange(int index): 更新选中的索引并通知 UI 刷新。
B. 车辆状态控制 (门锁与引擎盖/后备箱)
状态变量: 定义了四个布尔值,分别代表右侧门、左侧门、引擎盖 (Bonnet) 和后备箱 (Trunk) 的锁定状态,初始值均为 true (锁定)。
更新方法: 提供了四个独立的方法 (updateRightDoorLock 等) 来切换对应的状态。每次调用都会取反当前状态并触发 notifyListeners()。
C. 空调模式控制
isCoolSelected: 标记当前是否为制冷模式(true)还是制热模式。
updateCoolSelectedTab(): 切换制冷/制热状态。
D. 轮胎信息显示控制 (核心逻辑)
这部分代码包含了复杂的显示逻辑,用于控制轮胎详情的淡入或切换:
showTyreController(int index):
目的: 控制是否显示轮胎模型。
逻辑: 当从其他页面切换到轮胎页面 (index == 3) 时,先不立即显示轮胎,而是等待 400 毫秒(推测是为了等待汽车动画移动到屏幕中央),然后将 isShowTyre 设为 true。
反向逻辑: 当离开轮胎页面时,立即隐藏轮胎。
tyreStatusController(int index):
目的: 控制是否显示轮胎的具体状态文本(如胎压数值)。
逻辑: 与上面相反。当进入轮胎页面时,立即显示状态 (isShowTyreStatus = true)。
反向逻辑: 当离开轮胎页面时,延迟 400 毫秒再隐藏状态。

3. lib/constanins.dart

定义了应用的全局常量,包括颜色、间距和动画时长。

颜色系统:
primaryColor: 一种亮眼的浅蓝色 (#53F9FF),通常用于科技感、未来感强的界面,适合作为默认状态的高光色。
redColor: 红色 (#FF5368),专门用于警示,例如胎压过低 (isLowPressure == true) 时的字体或图标颜色。
布局系统:
defaultPadding: 统一的内边距(16.0),保证页面布局的整齐划一。
动效系统:
defaultDuration: 统一的动画时长(300毫秒),保证点击、切换等动效的一致性。

4. lib/screens/components

4.1. lib/screens/components/battery_status.dart

这是一个 Flutter 无状态组件(StatelessWidget),用于显示电动车的电池状态信息。

负责展示车辆的电池电量、续航里程、充电状态以及电压速度等关键信息。

构造函数与参数:
接收一个 BoxConstraints 对象(通常来自父组件的 LayoutBuilder),用于根据屏幕尺寸动态调整内部间距(如最后的 SizedBox)。
UI 结构:
头部信息:显示剩余里程 (220 mi) 和电量百分比 (62%)。
中部信息:显示充电状态 (Charging) 和剩余时间 (18 min)。
底部信息:通过 DefaultTextStyle 统一设置了速度 (22 mi/hr) 和电压 (232 v) 的样式,并使用 Spacer 和 SizedBox 进行了垂直布局分割。

4.2. lib/screens/components/door_lock.dart

通过 AnimatedSwitcher 实现一个带有缩放动画效果的车门锁状态切换按钮。

构造函数与参数:
press: 一个回调函数,当用户点击图标时触发(通常会调用 HomeController 中的 updateLock 方法)。
isLock: 布尔值,决定当前显示“锁上”图标还是“解锁”图标。
UI 逻辑:
使用 GestureDetector 捕获点击事件。
使用 AnimatedSwitcher 包裹两个 SVG 图标。
当 isLock 状态改变时,AnimatedSwitcher 会自动播放 ScaleTransition 缩放动画,平滑地在“锁”和“解锁”状态之间切换。

4.3. lib/screens/components/temp_details.dart

这是一个用于展示车辆空调温度控制界面的 Flutter 组件代码(TempDetails)。

构造函数:接收一个 HomeController 实例,用于监听空调模式(制冷/制热)的状态。
UI 结构:
顶部模式切换:使用 TempBtn 组件显示“Cool”(制冷)和“Heat”(制热)模式。根据 _controller.isCoolSelected 的布尔值来判断当前激活的是哪个模式。
中部目标温度:显示当前设定的目标温度(29°C),并配有上下箭头图标(目前仅作为装饰,未绑定逻辑)。
底部当前温度:显示车内(Inside)和车外(Outside)的当前温度。

4.4. lib/screens/components/tesla_bottom_navigationbar.dart

这段代码负责在屏幕底部显示四个图标(门锁、充电、温度、轮胎),用于在不同功能页面间切换。

组件功能:TeslaBottomNavigationBar 是一个无状态组件,接收当前选中索引 selectedTab 和点击回调 onTap。
UI 样式:
背景:纯黑色 (Colors.black)。
图标:使用 SvgPicture.asset 加载矢量图标。
颜色逻辑:当前选中的图标显示为主题色(primaryColor,浅蓝),未选中的图标显示为白色半透明 (Colors.white54)。
数据源:navIconSrc 列表定义了四个图标的路径,分别对应门锁、充电、温度和轮胎。

4.5. lib/screens/components/tmp_btn.dart

这是一个用于构建 Tesla 风格汽车中控界面中“温度模式选择按钮”的 Flutter 组件代码。

这段代码的作用是创建一个带有弹性动画效果(缩放和颜色变化)的交互式按钮,用于在制冷(Cool)和制热(Heat)模式之间切换。

构造函数参数:
svgSrc: 图标的路径(如 "assets/icons/coolShape.svg")。
title: 按钮下方的文本(如 "Cool""Heat")。
isActive: 布尔值,控制按钮当前是否被选中。默认为 false。
press: 点击回调函数,用于通知父组件更新状态。
activeColor: 选中时的高亮颜色。默认使用 constants.dart 中定义的 primaryColor(浅蓝色)。
UI 交互逻辑:
尺寸动画:使用 AnimatedContainer。当 isActive 为 true 时,按钮放大为 76x76;否则缩小为 50x50。
颜色与字体动画:使用 AnimatedDefaultTextStyle。选中时文字变为 activeColor 且加粗,未选中时为半透明白色 (Colors.white38)。
曲线效果:Curves.easeInOutBack 营造出一种“弹跳”的科技感,非常适合汽车中控的动效风格。

4.6. lib/screens/components/tyre_psi_card.dart

这段代码专门负责展示单个轮胎的详细状态(气压、温度、低气压警告)。

组件功能:TyrePsiCard 用于显示单个轮胎的信息。它根据传入的参数 isBottomTwoTyre 来判断是前轮还是后轮,并调整文本的布局方向(前轮文字正向,后轮文字反向)。
状态样式:
正常状态:白色半透明背景 (Colors.white10),主色调边框。
低气压状态:红色半透明背景 (redColor.withOpacity(0.1)),红色边框。
UI 细节:
气压值:使用 Text.rich 实现了数值大字体、单位小字体的排版效果。
警告文本:当气压过低时,显示 "LOW PRESSURE" 的警告语。

4.7. lib/screens/components/tyres.dart

这段代码的作用是在屏幕的四个角(左上、右上、右下、左下)定位四个轮胎的 SVG 图标,模拟汽车的俯视图布局。

函数功能:tyres 函数接收一个 BoxConstraints 参数(通常来自 LayoutBuilder),并返回一个包含四个 Positioned 小部件的列表。
定位逻辑:
使用 constrains.maxWidth 和 constrains.maxHeight 获取父容器的尺寸。
通过百分比(如 0.2)计算轮胎在屏幕上的位置,以确保在不同屏幕尺寸下保持相对位置。

5. lib/screens/home_screen.dart

这段代码是一个 Flutter 实现的小米 SU7 车辆控制界面(仿特斯拉风格),核心功能是通过底部导航切换不同车辆状态(车门锁、电池、温度、胎压),并附带流畅的分步动画效果。

这段代码定义了一个 HomeScreen 有状态组件,实现了 4 个核心车辆状态界面的切换和动画:
车门锁控制(默认界面,前后左右车门锁状态)
电池状态展示(附带电池图标和详情动画)
车内温度控制(冷热切换、温度详情动画)
轮胎胎压监测(4 个轮胎胎压分步展示动画)
所有界面切换和状态展示都通过 AnimationController 和 CurvedAnimation 实现了连贯的分步动画,提升了界面交互体验。

1. 依赖与初始化
依赖引入:引入了 Flutter 核心组件、SVG 解析库(展示车辆 / 电池图标)、自定义常量、控制器和数据模型。
混合混入:with TickerProviderStateMixin,这是 Flutter 中实现动画的必备混入,用于为 AnimationController 提供帧同步支持(避免内存泄漏)。
控制器与动画变量:
自定义业务控制器 _controller = HomeController():用于管理底部导航选中项、车门锁状态、胎压展示状态等业务逻辑。
3 个 AnimationController:分别对应电池、温度、胎压的动画时长控制。
多个 Animation<double>:对应每个场景下的分步动画(如电池先显示图标、再显示详情)。
2. 动画初始化方法(3 个核心)
每个动画场景都封装了独立的初始化方法,遵循「统一创建控制器 → 定义分步动画曲线 → 整理动画列表(按需)」的逻辑:
setupBatteryAnimation():电池动画(时长 600ms)
分步动画:先显示电池图标(_animationBattery,0.0~0.5 区间,即前 300ms),再显示电池详情(_animationBatteryStatus,0.6~1 区间,即 360ms~600ms),实现「先图标、后详情」的递进效果。
setupTempAnimation():温度动画(时长 1500ms)
三步动画:车辆偏移(_animationCarShift)→ 温度详情显示(_animationTempShowInfo)→ 冷热光晕显示(_animationCoolGlow),实现「车辆移动 → 详情展示 → 氛围强化」的连贯效果。
setupTyreAnimation():胎压动画(时长 1200ms)
分步动画:4 个轮胎胎压卡片依次展示(每个轮胎占一个时间区间,间隔 0.16),实现「从左前 → 右前 → 左后 → 右后」的逐个胎压展示效果,最后将 4 个动画存入 _tyreAnimations 列表方便后续遍历使用。
这里的核心是 Interval 曲线,它可以将 AnimationController 的 0~1 时间区间,分割成多个子区间,实现「分步执行」的动画效果,而不是所有动画同时开始和结束。
3. 生命周期管理
initState():组件创建时初始化所有动画配置,确保动画变量在组件构建前完成初始化,避免空指针异常。
dispose():组件销毁时释放所有 AnimationController 资源,这是 Flutter 动画开发的最佳实践,必须执行,否则会导致内存泄漏。
4. 构建方法(核心 UI 与动画绑定)
AnimatedBuilder:核心动画构建组件,通过 Listenable.merge() 监听所有控制器(业务控制器 + 3 个动画控制器)的变化,当任意控制器状态改变时,重新构建 UI,实现动画和状态的同步更新。
Scaffold 结构:
底部导航:TeslaBottomNavigationBar,通过 onTap 回调绑定动画触发和业务状态更新。
主体内容:SafeArea + LayoutBuilder,LayoutBuilder 用于获取父组件的宽高约束(constrains),实现自适应布局(避免不同设备上的 UI 错乱)。
5. 底部导航回调(动画触发核心逻辑)
底部导航的 onTap 是整个界面的「动画触发器」,核心逻辑是「选中对应标签 → 播放对应动画;离开对应标签 → 反向播放动画(收回界面)」:
forward():播放动画(从 01)。
reverse(from: value):反向播放动画(从指定值 → 0),from 参数用于指定反向播放的起始点,让动画收回更自然。
6. 界面元素与动画绑定
所有动态展示的 UI 都通过「透明度(Opacity)」、「位置(AnimatedPositioned)」、「缩放(ScaleTransition)」与动画变量绑定,实现动画效果:
车门锁界面:使用 AnimatedPositioned + AnimatedOpacity,切换非默认标签时,车门锁控件向屏幕中心移动并渐隐,实现「收回」效果。
电池界面:Opacity 绑定 _animationBattery(电池图标)和 _animationBatteryStatus(电池详情),实现分步显示。
温度界面:车辆偏移通过 Positioned 的 left 绑定 _animationCarShift,详情和光晕通过 Opacity 绑定对应动画变量,冷热光晕切换使用 AnimatedSwitcher 实现平滑过渡。
胎压界面:通过 GridView.builder 遍历胎压数据,使用 ScaleTransition 绑定 _tyreAnimations 中的对应动画,实现 4 个轮胎卡片的分步缩放显示。

📢关键点

demoPsiList 与 TyrePsi:代码中使用了 demoPsiList[index] 作为胎压数据,这是一个模拟的胎压数据列表,需要确保 demoPsiList 是 List<TyrePsi> 类型,且包含 4 个元素,否则会报数组越界异常。
defaultDuration 与 defaultPadding:来自自定义常量文件 constanins.dart(注意拼写可能是 constants.dart 的笔误),用于统一管理动画时长和内边距,保证项目样式一致性。
NeverScrollableScrollPhysics():胎压界面的 GridView 设置了该物理滚动属性,禁止滚动,因为胎压卡片是通过网格布局直接铺满屏幕,无需滚动。
UniqueKey():AnimatedSwitcher 中切换图片时使用 UniqueKey(),确保 AnimatedSwitcher 能识别子组件的变化,从而触发切换动画(否则不会有过渡效果)。
总结
这段代码的核心是 「业务状态 + 分步动画」的结合,通过 HomeController 管理业务逻辑,通过 3 个 AnimationController 实现不同场景的分步动画。
动画的关键是 Interval 曲线,它实现了「先执行 A 动画,再执行 B 动画」的递进效果,提升了界面交互的流畅性。
开发规范上,遵循了「动画初始化 → 构建 UI → 资源释放」的生命周期流程,避免了内存泄漏,是 Flutter 动画开发的典型优质示例。
布局上使用 LayoutBuilder 实现自适应,保证了不同设备上的 UI 一致性,具备实际项目的可落地性。

6. lib/main.dart

这是一个基于 Flutter 框架编写的鸿蒙(HarmonyOS)应用入口文件。

这是一个基于 Flutter 框架编写的鸿蒙(HarmonyOS)应用入口文件。
代码解析:
状态栏设置:将状态栏设置为透明,并将图标亮度设为浅色(白色)。
屏幕方向锁定:强制应用仅支持竖屏模式(portraitUp 和 portraitDown)。
应用主题:
深色模式:使用 Brightness.dark。
背景色:将 Scaffold 的背景色设为纯黑。
按钮样式:去除了 ElevatedButton 的阴影(elevation: 0),并设置了圆角边框。
导航:应用启动后直接进入 HomeScreen。

7. 效果验证

7.1. 门锁页面

7.2. 充电页面

在这里插入图片描述

7.3. 温度页面

7.4. 轮胎页面

在这里插入图片描述

欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐