鸿蒙原生应用实战:骑行页的扫码开锁与计时切换

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 块结构

  1. Header — 白色背景 + "骑行"标题
  2. RideCard — 渐变状态卡(核心)
  3. 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(骑行)+渐变RideCard(📷扫码开锁/对准车把二维码扫描/白色"开始扫码"按钮)+骑行记录(今天09:12 25分钟 3.2km ¥1.0/昨天17:40 18分钟 2.1km ¥1.0/8月11日 42分钟 6.8km ¥2.0)

项目源码开源:https://gitee.com/codenestFlow/HarmonyOSHub

二、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 标准"——"标题组件复用"

结束锁车交互 · 骑行中状态点击"结束骑行·锁车"按钮后屏幕底部弹出"已锁车,费用 ¥1.0"Toast,渐变卡切换回"扫码开锁"形态,演示 @State riding 状态机的完整循环

五、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:1225 分钟3.2 km¥1.0
昨天 17:4018 分钟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 个设计哲学

  1. 状态优先——当前骑行状态清晰可见
  2. 操作优先——大号按钮引导行动
  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 的全局数据"——"完整数据流"

骑行中状态 · 点击"开始扫码"按钮后渐变卡切换为骑行中形态:00:12:36 大号计时器 + "骑行中·1.5km·¥1.0" + 🚲 emoji + "结束骑行·锁车"白色按钮,骑行记录列表保持显示

七、总结:青蓝 + 状态切换 + 骑行记录

App 33 骑行页一句话用青蓝(#2D9CDB)组织一个"状态卡 + 记录"的骑行页——渐变 RideCard 用 @State riding 布尔状态在"扫码开锁"和"骑行计时"两种形态间切换,白色按钮引导"开始扫码/结束锁车"操作,3 条骑行记录用日期 + 费用 + ⏱️时长 + 📏距离完整展示历史。

3 个设计亮点

  1. @State riding 状态切换——if/else 条件渲染两种 UI(扫码 ↔ 计时)
  2. 渐变卡 + 白按钮——青蓝渐变背景 + 高对比白色行动按钮
  3. 骑行记录双行卡——日期/费用 + ⏱️时长/📏距离 完整数据

主题色设计逻辑:青蓝 = 共享单车 + 运动的经典蓝——"骑行页用青蓝,因为这是共享单车行业的品牌共识"——与首页/地图同色——"品牌色贯穿"

与系列呼应:渐变卡(系列)、@State 状态(系列)、Button(26/27/28)、SectionTitle(系列)、ForEach 列表(系列)、emoji 图标(系列)——"33 骑行把系列的状态 + 渐变 + 列表手法组合出'骑行'场景"

体验细节:状态切换、计时器、费用透明、按钮引导、记录完整——"骑行页的核心 = 让用户'3 秒开锁 + 骑行完 3 秒锁车'"

可扩展性展望:真实计时器、GPS 轨迹、骑行速度、费用结算、优惠券抵扣、骑行分享——"demo 的骑行页骨架完整"

七、扩展思考:骑行页的状态机与设计哲学

7.1 骑行页的"状态机"

完整状态机

[扫码开锁] --点击"开始扫码"--> [骑行中(计时)]
[骑行中]   --点击"结束骑行·锁车"--> [扫码开锁]

"两态状态机"——"循环往复"——"骑行闭环"——"开锁 → 骑行 → 锁车"——"状态的完整循环"——"业务的状态建模"——"布尔状态的循环"

7.2 骑行页的"转化路径"

完整骑行漏斗

看状态卡(扫码开锁)→ 点击开始扫码 → 骑行中(计时)→ 点击结束锁车 → 看骑行记录

"从开锁到记录的闭环"——"骑行全流程"——"操作 + 记录"——"执行 + 历史"——"骑行页的转化链"

7.3 骑行页的"信息架构"

3 层信息

  1. L1 标题(Header)——"骑行"
  2. L2 状态(RideCard)——"当前在骑行吗"
  3. L3 历史(TripList)——"骑过什么"

"3 层渐进式"——"从标题到当前到历史"——"当前状态优先"——"历史辅助"——"渐进式披露"

7.4 骑行页的"业务建模"

Trip 模型 6 字段(id/date/duration/dist/cost)——"6 字段建模"——"骑行记录的核心"——"最小可用集"——加轨迹(track)、加均速(speed)、加碳减排(carbon)即可扩展——"数据模型的扩展点"

7.5 骑行页的"对比与统一"

统一:3 记录同结构(日期/费用 + 时长/距离)——"记录项的统一"对比:3 记录数据不同(日期/时长/距离/费用)——"差异在数据"——"结构同构 + 数据异构"

7.6 骑行页的"设计哲学"

骑行页的 3 个设计哲学

  1. 状态优先——骑行状态一眼可见
  2. 操作优先——大按钮引导开锁/锁车
  3. 数据优先——费用/时长/距离透明

"状态 + 操作 + 数据的骑行页"——"工具型骑行页的设计原则"——"从哲学看设计"——"这套方法论可直接迁移到任何骑行/运动类 App"

7.7 骑行页的"终评"

App 33 骑行页综合评估——"三区结构 + 青蓝主题 + 完整状态机"——"骑行页的完成度评级"——"一个可上线级的骑行页"——"系列操作型页面的标杆"——"demo 的高完成度"

再次开锁交互 · 回到扫码状态后再次点击"开始扫码"按钮,屏幕底部弹出"开锁成功,开始计费"Toast,渐变卡再次切换为骑行中计时形态,演示状态循环的可重复性

八、彩蛋:骑行页的细节设计

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 的可复用范式。

Logo

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

更多推荐