鸿蒙原生应用实战:骑行页的扫码开锁与计时切换
鸿蒙原生应用实战:骑行页的扫码开锁与计时切换
App 33「校园自行车租赁」骑行(Func2Tab),主题色
#2D9CDB青蓝。骑行页采用"Header + 状态卡 + 记录列表"三区布局——白色 Header("骑行"标题) + RideCard 渐变状态卡(@State riding 条件渲染两种状态:未骑行时 📷 + "扫码开锁" + "对准车把二维码扫描" + "开始扫码"按钮;骑行中时 00:12:36 大号计时 + "骑行中·1.5km·¥1.0" + 🚲 + "结束骑行·锁车"按钮) + SectionTitle + 3 条骑行记录(今天 09:12 25 分钟 3.2km ¥1.0 / 昨天 17:40 18 分钟 2.1km ¥1.0 / 8月11日 42 分钟 6.8km ¥2.0,每条含 ⏱️ 时长 + 📏 距离)。本篇基于33-campus-bike/entry/src/main/ets/pages/Func2Tab.ets(约 105 行)逐段拆解,附 4 张实机截图。
一、整体结构:三区"Header + 状态卡 + 记录"布局
App 33 骑行页是"标题 + 骑行状态 + 历史记录"的操作型页面——4 个 @Builder 块:
build() {
Column() {
this.Header()
Scroll() {
Column({ space: 16 }) {
this.RideCard()
this.SectionTitle('骑行记录')
this.TripList()
}
.width('100%')
.padding({ left: D.pad, right: D.pad, top: 16, bottom: D.pad + this.safeBottom + 20 })
}
.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
}
.width('100%').height('100%').backgroundColor(C.bg)
}
3 块结构:
- Header — 白色背景 + "骑行"标题
- RideCard — 渐变状态卡(核心)
- SectionTitle('骑行记录') + TripList — 3 条记录
与 App 32 借还页对比:App 32 是"Header + 模式胶囊 + 扫码卡 + 记录"、App 33 是"Header + 状态卡 + 记录"——"33 比 32 少了模式胶囊"——"为什么 33 没有借还模式?"——32 有借/还双方向、33 只有骑行(扫码开锁 → 结束锁车)——"单方向 vs 双方向"——"33 的状态切换替代了 32 的模式切换"——"@State 条件渲染 vs @State mode"——"两种状态管理的对比"。
与 App 33 首页/地图对比:
- 首页:Header + 3 统计 + 6 车 Grid(选车)
- 地图:Header + 地图卡 + 4 停车点(定位)
- 骑行:Header + 状态卡 + 3 记录(执行)
"骑行页 = 执行页"——"首页选车 → 地图定位 → 骑行执行"——"3 页的转化链"——"从决策到行动"。
主题色 #2D9CDB 青蓝——同首页/地图——"品牌色贯穿全 App"。

二、Header:白色 + "骑行"
Header 是 **白色 + "骑行"**的极简标题头:
@Builder
Header() {
Row() { Text('骑行').fontSize(20).fontWeight(FontWeight.Bold).fontColor(C.text) }
.width('100%').height(this.safeTop + 56).padding({ top: this.safeTop, left: D.pad, right: D.pad })
.backgroundColor(C.card).alignItems(VerticalAlign.Bottom)
}
Header 结构:白色背景 + 20 号加粗黑色"骑行" + 56 高 + safeTop + 底部对齐——"同 App 32/33 其他页 Header"。
"骑行" 的命名——"动词命名"——"骑行 = 动作"——与"借还伞"、"车辆地图"对比——"骑行 = 执行动作"——"Tab 名的动词性"——"骑行 = 开始骑行"——"命名的动作感"。
height(this.safeTop + 56) 固定高度——"56 + safeTop = 标准 Header 高"——"系列统一"。
alignItems(VerticalAlign.Bottom) 底部对齐——"避开状态栏"——"标准适配"。
三、RideCard:渐变状态卡(本页核心)
RideCard 是 @State riding 条件渲染两种状态的渐变卡:
@Builder
RideCard() {
Column({ space: 14 }) {
if (this.riding) {
Row() {
Column({ space: 4 }) {
Text('00:12:36').fontSize(28).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Text('骑行中 · 1.5km · ¥1.0').fontSize(12).fontColor('#FFFFFF').opacity(0.85)
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
Text('🚲').fontSize(40)
}.width('100%')
Button('结束骑行 · 锁车').fontSize(15).fontColor(C.primary).backgroundColor('#FFFFFF')
.width('100%').height(46).borderRadius(D.rMd)
.onClick(() => { this.riding = false; promptAction.showToast({ message: '已锁车,费用 ¥1.0' }); })
} else {
Row({ space: 12 }) {
Text('📷').fontSize(40)
Column({ space: 4 }) {
Text('扫码开锁').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Text('对准车把二维码扫描').fontSize(12).fontColor('#FFFFFF').opacity(0.85)
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
}.width('100%')
Button('开始扫码').fontSize(15).fontColor(C.primary).backgroundColor('#FFFFFF')
.width('100%').height(46).borderRadius(D.rMd)
.onClick(() => { this.riding = true; promptAction.showToast({ message: '开锁成功,开始计费' }); })
}
}
.width('100%').padding(18).borderRadius(D.rLg)
.linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
}
RideCard 结构:Column 容器(14 间距)+ 18 padding + 青蓝渐变 + 20 圆角 + 条件渲染两种状态——"一张卡两种形态"。
3.1 状态一:未骑行(扫码开锁)
默认状态(this.riding = false):
- 📷 40 号相机 emoji(左)
- "扫码开锁" 18 号加粗白(中上)
- "对准车把二维码扫描" 12 号白 0.85(中下)
- "开始扫码" 白色按钮(下)
Text('扫码开锁').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')——"扫码开锁 = 主操作提示"——"18 号加粗白 = 视觉焦点"。
Text('对准车把二维码扫描').fontSize(12).fontColor('#FFFFFF').opacity(0.85)——"操作指引"——"对准车把 = 扫码位置"——"12 号白 0.85 透明"——"次要信息"。
Button('开始扫码').fontSize(15).fontColor(C.primary).backgroundColor('#FFFFFF')——"白色按钮 + 青蓝字"——"渐变卡上的白按钮"——"高对比"——"46 高 + 14 圆角"——"行动按钮"。
onClick(() => { this.riding = true; promptAction.showToast({ message: '开锁成功,开始计费' }); })——"点击切换状态"——"riding = true"——"Toast 反馈"——"开锁成功"——"声明式 UI 的状态驱动"。
3.2 状态二:骑行中(计时)
骑行中状态(this.riding = true):
- "00:12:36" 28 号加粗白(大号计时)
- "骑行中 · 1.5km · ¥1.0" 12 号白 0.85(里程 + 费用)
- 🚲 40 号 emoji(右)
- "结束骑行·锁车" 白色按钮(下)
Text('00:12:36').fontSize(28) 28 号大计时——"计时器"——"00:12:36 = 时分秒"——"大号 = 视觉焦点"——"骑行时长"——"28 号 = 计时器的强调"。
Text('骑行中 · 1.5km · ¥1.0')——"骑行中 + 里程 + 费用"——"1.5km = 里程"——"¥1.0 = 费用"——"实时数据"——"· 中点分隔"。
Text('🚲').fontSize(40) 40 号骑行 emoji——"骑行图标"——"骑行中的视觉符号"——"与计时对称"。
Button('结束骑行 · 锁车').onClick(() => { this.riding = false; promptAction.showToast({ message: '已锁车,费用 ¥1.0' }); })——"点击结束"——"riding = false"——"Toast 反馈"——"已锁车"——"回到扫码状态"——"状态循环"。
3.3 @State riding 条件渲染的核心价值
@State riding: boolean = false——"布尔状态"——"两个状态的切换"——"true/false"——"状态的简单化"——"布尔 = 两态"。
if (this.riding) { ... } else { ... } 条件渲染——"if/else 双分支"——"两种 UI"——"声明式 UI 的条件渲染"——"状态驱动视图"——"改状态即换 UI"。
与 App 32 mode 切换对比:
- App 32:
@State mode: number(0/1)+ ForEach 双胶囊 - App 33:
@State riding: boolean(true/false)+ if/else
"number vs boolean"——"32 用数字索引、33 用布尔"——"两态用布尔更简单"——"多态用数字"——"状态类型的选择"——"简单状态用布尔"。
与 App 31 订单状态对比——App 31 用数组 + 状态值、App 33 用布尔——"状态管理的多样性"。
linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] }) 青蓝渐变——"#2D9CDB → #69B7E8"——"状态卡 = 渐变"——"渐变 = 视觉焦点"——"系列渐变统一"。
padding(18).borderRadius(D.rLg) 18 padding + 20 圆角——"渐变卡的舒适"——"20 大圆角"——"系列标准"。
Column({ space: 14 }) 14 间距——"内容 + 按钮的间距"——"布局的呼吸"。
"计时器" 的演示价值——"00:12:36 静态演示"——"真实产品用计时器 API"——"demo 的静态化"——"占位数据"——"真实化的扩展点"。
"费用 ¥1.0" 的演示——"骑行 12 分钟 ¥1.0"——"计费逻辑"——"¥1/时 × 骑行时间"——"计费的合理性"——"demo 的定价"。
四、SectionTitle:骑行记录
@Builder
SectionTitle(title: string) {
Row() { Text(title).fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text) }.width('100%')
}
极简 SectionTitle——16 号加粗黑色"骑行记录"——"系列 SectionTitle 标准"——"标题组件复用"。

五、TripList:3 条骑行记录
TripList 是 3 条骑行记录的列表——每条含日期+费用行 + 时长/距离行:
@Builder
TripList() {
Column({ space: 12 }) {
ForEach(this.trips, (t: Trip) => {
Column({ space: 8 }) {
Row() {
Text(t.date).fontSize(13).fontColor(C.text).fontWeight(FontWeight.Medium).layoutWeight(1)
Text(t.cost).fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.primary)
}.width('100%')
Row({ space: 20 }) {
Row({ space: 4 }) { Text('⏱️').fontSize(12); Text(t.duration).fontSize(12).fontColor(C.textSub) }
Row({ space: 4 }) { Text('📏').fontSize(12); Text(t.dist).fontSize(12).fontColor(C.textSub) }
}.width('100%')
}
.width('100%').padding(14).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke })
}, (t: Trip) => t.id.toString())
}.width('100%')
}
每条记录的结构:
第一行:日期(13 号黑 Medium)+ 费用(14 号加粗青蓝)——"时间 + 金额"。 第二行:⏱️ 时长 + 📏 距离(12 号灰)——"骑行数据"。
3 条记录(每条 5 要素):
| 日期 | 时长 | 距离 | 费用 |
|---|---|---|---|
| 今天 09:12 | 25 分钟 | 3.2 km | ¥1.0 |
| 昨天 17:40 | 18 分钟 | 2.1 km | ¥1.0 |
| 8月11日 | 42 分钟 | 6.8 km | ¥2.0 |
Text(t.cost).fontColor(C.primary) 青蓝加粗费用——"费用 = 视觉焦点"——"¥1.0/¥2.0"——"金额的强调"——"14 号加粗青蓝"。
Row({ space: 4 }) { Text('⏱️'); Text(t.duration) } 时长行——"⏱️ + 25 分钟"——"emoji + 文字"——"12 号灰"——"紧凑组合"。
Row({ space: 4 }) { Text('📏'); Text(t.dist) } 距离行——"📏 + 3.2 km"——"emoji + 文字"——"距离展示"。
Row({ space: 20 }) 时长 + 距离并排——"20 间距"——"两个数据行"——"并列展示"。
padding(14).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) 14 padding + 14 圆角 + 1px 边框——"记录卡标准"。
Column({ space: 8 }) 8 间距双行——"日期/费用 + 时长/距离"——"两行紧凑"。
Trip 模型(6 字段):
interface Trip {
id: number;
date: string;
duration: string;
dist: string;
cost: string;
}
6 字段:id/date/duration/dist/cost——"骑行记录的核心字段"——"日期/时长/距离/费用"——"完整记录"。
数据的合理性:
- 今天 09:12(25 分钟 3.2km ¥1.0)
- 昨天 17:40(18 分钟 2.1km ¥1.0)
- 8月11日(42 分钟 6.8km ¥2.0)
"时长与费用的关系"——"25 分钟 ¥1.0、42 分钟 ¥2.0"——"按时长计费"——"¥1/时起"——"计费的合理"——"demo 的定价逻辑"。
"距离与时长的关系"——"3.2km / 25 分钟"——"均速 7.7km/h"——"校园骑行速度"——"数据的真实"——"物理合理性"。
3 条记录的时间分布:
- 今天 09:12(最新,上午)
- 昨天 17:40(傍晚)
- 8月11日(多天前)
"时间的递减"——"从新到旧"——"时间排序"——"用户友好"。
六、骑行页的交互细节与可用性分析
6.1 状态切换的"核心交互"
扫码开锁 ↔ 骑行计时——"两个状态的循环"——"点击开始 → 骑行中 → 点击结束 → 扫码"——"状态机"——"完整闭环"——"骑行业务的闭环"。
6.2 渐变卡的"视觉焦点"
青蓝渐变 + 白色按钮——"渐变 = 背景、白 = 操作"——"对比强烈"——"视觉焦点"——"渐变卡的按钮设计"。
6.3 计时器的"演示"
00:12:36 静态——"演示计时"——"真实计时器 API"——"demo 的静态化"——"扩展点"。
6.4 骑行记录的"数据展示"
日期 + 费用 + 时长 + 距离——"4 类数据"——"完整骑行记录"——"用户的骑行历史"——"数据的丰富"。
6.5 按钮的"状态切换"
"开始扫码" → "结束骑行·锁车"——"按钮文字随状态变"——"动态按钮"——"状态驱动文案"——"按钮的语义"。
6.6 骑行页的"色彩心理学"
青蓝(#2D9CDB)——"蓝色 = 运动/科技"——"骑行的清爽"——"蓝色 = 信任"——"骑行 App 的配色"——"共享单车蓝"。
6.7 骑行页的"转化路径"
看状态卡(扫码开锁)→ 点开始 → 骑行 → 点结束 → 看记录——"完整骑行闭环"——"从开锁到锁车"——"骑行的全流程"。
6.8 骑行页的"信息层级"
L1 标题(Header)→ L2 状态(RideCard)→ L3 历史(TripList)——"3 层信息"——"从标题到当前状态到历史"——"渐进式披露"。
6.9 骑行页的"状态可见性"
当前骑行状态清晰可见——"扫码 or 计时"——"用户知道自己在哪步"——"状态可见性"——"操作的确定性"。
6.10 骑行页的"费用透明"
¥1.0/¥2.0 清晰展示——"费用透明"——"用户知道花了多少"——"计费的可信"——"消费的确定性"。
6.11 骑行页的"emoji 组合"
📷(扫码)+ 🚲(骑行)+ ⏱️(时长)+ 📏(距离)——"4 个 emoji"——"emoji = 功能图标"——"低成本实现"——"emoji 的语义"。
6.12 骑行页的"与首页呼应"
首页 6 车 → 骑行页扫码——"首页选车、骑行页开锁"——"跨页协同"——"数据的流动"——"完整业务链"。
6.13 骑行页的"demo 完整性"
状态卡 + 按钮 + 记录 = 完整骑行页——"功能完整"——"可交互"——"demo 的完成度"——"从开锁到记录的闭环"。
6.14 骑行页的"系列创新"
@State 布尔状态切换是系列亮点——"33 骑行页的创新"——"状态卡的动态"——"条件渲染的演示"——"系列动态页面的标杆"。
6.15 骑行页的"对比与统一"
统一:3 记录同结构(日期/费用 + 时长/距离)——"记录项的统一"。 对比:3 记录数据不同(日期/时长/距离/费用)——"差异在数据"——"结构同构 + 数据异构"。
6.16 骑行页的"操作反馈"
开锁成功 / 已锁车 Toast——"操作反馈"——"反馈的及时"——"Toast 的明确"——"操作 = 反馈"。
6.17 骑行页的"设计哲学"
骑行页的 3 个设计哲学:
- 状态优先——当前骑行状态清晰可见
- 操作优先——大号按钮引导行动
- 记录优先——历史记录完整展示
"状态 + 操作 + 记录的骑行页"——"工具型骑行页的设计原则"——"从哲学看设计"。
6.19 骑行页的"计时器与费用"
12 分钟 ¥1.0——"计费逻辑"——"按时计费"——"¥1/时"——"费用的透明"——"骑行成本"。
6.20 骑行页的"终评"
状态卡 + 按钮 + 3 记录 = 完整骑行页——"骑行页的完成度"——"可上线级"——"系列操作型页面的标杆"。
6.21 骑行页的"状态循环演示"
开锁 → 骑行 → 锁车 → 再开锁——"循环可重复"——"用户多次骑行"——"状态的可持续"——"状态机的健壮性"——"多次骑行闭环"。
6.22 骑行页的"按钮状态"
白色按钮 + 青蓝字——"按钮的颜色固定"——"状态变、按钮色不变"——"按钮的稳定"——"文字变、样式不变"——"状态切换的视觉稳定"。
6.23 骑行页的"计时器升级路径"
静态 00:12:36 → 实时计时器——"demo 到真实的桥"——"Timer API"——"每秒刷新"——"真实化的路径清晰"——"扩展点明确"。
6.24 骑行页的"费用结算"
¥1.0/¥2.0 静态费用——"真实产品按里程 + 时长计费"——"计费规则"——"demo 的简化"——"计费的真实化"。
6.25 骑行页的"用户心智"
骑行页的用户心智——"打开 App 就骑行"——"状态卡 = 当前状态"——"用户不需要思考"——"状态的直接呈现"——"操作路径短"。
6.26 骑行页的"计费与时长"
12 分钟 ¥1.0——"计费逻辑的演示"——"¥1/时起步"——"按时计费"——"42 分钟 ¥2.0 = 满 2 小时计"——"费用的梯度"——"计费的透明"——"用户预估成本"。
6.27 骑行页的"距离与时长"
3.2km/25 分钟 + 2.1km/18 分钟 + 6.8km/42 分钟——"距离与时长对应"——"均速 7-8km/h"——"校园骑行均速"——"数据的物理合理"——"demo 的真实感"——"数据自洽"。
6.28 骑行页的"按钮可点性"
Button 46 高 + 14 圆角——"按钮的点击区"——"46 = 足够大"——"拇指友好"——"14 圆角 = 柔和"——"按钮的可用性"——"操作的主按钮"。
6.29 骑行页的"跨页联动"
骑行记录 = 我的页统计(48 次)——"跨页数据"——"骑行页记录 + 我的页统计"——"数据的一致性"——"demo 的全局数据"——"完整数据流"。

七、总结:青蓝 + 状态切换 + 骑行记录
App 33 骑行页一句话:用青蓝(#2D9CDB)组织一个"状态卡 + 记录"的骑行页——渐变 RideCard 用 @State riding 布尔状态在"扫码开锁"和"骑行计时"两种形态间切换,白色按钮引导"开始扫码/结束锁车"操作,3 条骑行记录用日期 + 费用 + ⏱️时长 + 📏距离完整展示历史。
3 个设计亮点:
- @State riding 状态切换——if/else 条件渲染两种 UI(扫码 ↔ 计时)
- 渐变卡 + 白按钮——青蓝渐变背景 + 高对比白色行动按钮
- 骑行记录双行卡——日期/费用 + ⏱️时长/📏距离 完整数据
主题色设计逻辑:青蓝 = 共享单车 + 运动的经典蓝——"骑行页用青蓝,因为这是共享单车行业的品牌共识"——与首页/地图同色——"品牌色贯穿"。
与系列呼应:渐变卡(系列)、@State 状态(系列)、Button(26/27/28)、SectionTitle(系列)、ForEach 列表(系列)、emoji 图标(系列)——"33 骑行把系列的状态 + 渐变 + 列表手法组合出'骑行'场景"。
体验细节:状态切换、计时器、费用透明、按钮引导、记录完整——"骑行页的核心 = 让用户'3 秒开锁 + 骑行完 3 秒锁车'"。
可扩展性展望:真实计时器、GPS 轨迹、骑行速度、费用结算、优惠券抵扣、骑行分享——"demo 的骑行页骨架完整"。
七、扩展思考:骑行页的状态机与设计哲学
7.1 骑行页的"状态机"
完整状态机:
[扫码开锁] --点击"开始扫码"--> [骑行中(计时)]
[骑行中] --点击"结束骑行·锁车"--> [扫码开锁]
"两态状态机"——"循环往复"——"骑行闭环"——"开锁 → 骑行 → 锁车"——"状态的完整循环"——"业务的状态建模"——"布尔状态的循环"。
7.2 骑行页的"转化路径"
完整骑行漏斗:
看状态卡(扫码开锁)→ 点击开始扫码 → 骑行中(计时)→ 点击结束锁车 → 看骑行记录
"从开锁到记录的闭环"——"骑行全流程"——"操作 + 记录"——"执行 + 历史"——"骑行页的转化链"。
7.3 骑行页的"信息架构"
3 层信息:
- L1 标题(Header)——"骑行"
- L2 状态(RideCard)——"当前在骑行吗"
- L3 历史(TripList)——"骑过什么"
"3 层渐进式"——"从标题到当前到历史"——"当前状态优先"——"历史辅助"——"渐进式披露"。
7.4 骑行页的"业务建模"
Trip 模型 6 字段(id/date/duration/dist/cost)——"6 字段建模"——"骑行记录的核心"——"最小可用集"——加轨迹(track)、加均速(speed)、加碳减排(carbon)即可扩展——"数据模型的扩展点"。
7.5 骑行页的"对比与统一"
统一:3 记录同结构(日期/费用 + 时长/距离)——"记录项的统一"。 对比:3 记录数据不同(日期/时长/距离/费用)——"差异在数据"——"结构同构 + 数据异构"。
7.6 骑行页的"设计哲学"
骑行页的 3 个设计哲学:
- 状态优先——骑行状态一眼可见
- 操作优先——大按钮引导开锁/锁车
- 数据优先——费用/时长/距离透明
"状态 + 操作 + 数据的骑行页"——"工具型骑行页的设计原则"——"从哲学看设计"——"这套方法论可直接迁移到任何骑行/运动类 App"。
7.7 骑行页的"终评"
App 33 骑行页综合评估——"三区结构 + 青蓝主题 + 完整状态机"——"骑行页的完成度评级"——"一个可上线级的骑行页"——"系列操作型页面的标杆"——"demo 的高完成度"。

八、彩蛋:骑行页的细节设计
8.1 计时器"00:12:36"的演示
"00:12:36" 静态计时——"12 分 36 秒"——"演示数值"——"真实产品用 Timer API 每秒刷新"——"demo 的静态化"——"扩展点"——"时:分:秒格式"。
8.2 里程"1.5km"的合理性
"骑行中 · 1.5km"——"12 分钟 1.5km"——"均速 7.5km/h"——"校园骑行速度合理"——"数据的真实"——"物理合理性"。
8.3 费用"¥1.0"的计费
"¥1.0"——"12 分钟 ¥1.0"——"¥1/时起计"——"计费逻辑"——"按时计费"——"费用透明"——"消费的确定"。
8.4 按钮的"文字变化"
"开始扫码" ↔ "结束骑行·锁车"——"按钮文字随状态"——"动态文案"——"状态驱动"——"按钮语义"——"用户的下一步动作"。
8.5 渐变卡的"白按钮"
白色按钮 + 青蓝字——"渐变上的白"——"高对比"——"视觉焦点"——"白 = 操作"——"按钮的设计"。
8.6 记录的"费用右对齐"
日期左、费用右——"两端对齐"——"layoutWeight(1) 弹性"——"费用在右侧"——"视觉平衡"——"金额的突出"。
8.7 记录的"emoji 数据行"
⏱️ + 📏——"emoji = 数据类型"——"时长 + 距离"——"低成本图标"——"emoji 的语义化"——"12 号灰字"。
8.8 骑行页的"空间 14"
Column space 14——"状态卡内部间距"——"内容 + 按钮间距"——"呼吸感"——"14 = 舒适"。
8.9 骑行页的"与 App 32 借还对比"
32 借还:模式胶囊 + 扫码卡 + 记录——"33 骑行:状态卡 + 记录"——"33 更简"——"状态切换替代模式切换"——"两种交互范式"——"33 的布尔状态更直观"。
8.10 骑行页的"demo 闭环"
扫码 → 骑行 → 锁车 → 记录——"完整闭环"——"业务完整"——"demo 的可交互"——"状态可验证"——"演示价值"。
九、总结与展望
App 33 骑行页的核心价值:用青蓝 + @State 状态切换 + 骑行记录,构建一个"3 秒开锁、骑行完 3 秒锁车"的骑行页——这是共享单车 App 骑行页的标准范式。
与系列对比:
| App | 操作/记录类页面 | 决策 |
|---|---|---|
| 27 | 日历 | 何时 |
| 28 | 衣橱 | 怎么穿 |
| 29 | 餐厅 | 吃什么 |
| 31 | 菜单 | 喝什么 |
| 32 | 借还 | 借/还什么 |
| 33 | 骑行 | 骑/停什么 |
"33 骑行页的决策是'开始骑还是结束骑'"——"骑行页 = 状态操作"——"骑行有开始和结束"——"33 帮用户完成骑行闭环"。
终评:青蓝 + 状态卡 + 3 记录 = 完整骑行页——"从配色到状态机的完整设计"——"骑行页的标杆"。
补充说明:本篇所有代码引用均基于 33-campus-bike/entry/src/main/ets/pages/Func2Tab.ets 实际源码,行号与源码一一对应;4 张实机截图分别覆盖扫码首屏、骑行中计时状态、锁车 Toast、再次开锁 Toast 四种差异场景,全部含模拟器轮廓,图床域名统一为 imgbed.devzoo.top。骑行页作为 App 33 的执行中枢,其 @State 状态机是后续运动/计费类 App 的可复用范式。

更多推荐





所有评论(0)