鸿蒙原生应用 ArkUI 实战:双卡分离表单 + 三档提醒胶囊 —— 续费添加页的录入架构
鸿蒙原生应用 ArkUI 实战:双卡分离表单 + 三档提醒胶囊 —— 续费添加页的录入架构
App 55「自动续费提醒」添加页(Func1Tab),主题色
#FF6B6B珊瑚红,4 个 Tab 分别为首页(⏰)、添加(➕)、日历(📅)、我的(👤)。本篇基于55-renewal-reminder/entry/src/main/ets/pages/Func1Tab.ets(共 97 行)逐段拆解,附 4 张实机截图。

一、整体结构:三区"Header + 表单卡 + 提醒卡"布局
添加页是"服务信息录入 + 提醒规则设置"的组合布局——2 个 @Builder 块 + 1 个按钮:
build() {
Column() {
this.Header()
Scroll() {
Column({ space: 16 }) {
this.FormCard()
this.RemindCard()
Button('添加提醒').fontSize(15).fontColor('#FFFFFF').backgroundColor(C.primary)
.width('100%').height(48).borderRadius(D.rMd)
.onClick(() => { promptAction.showToast({ message: this.name.length > 0 ? '提醒已添加' : '请填写服务名称' }); })
}
.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 块结构:FormCard(四件套服务表单)→ RemindCard(提前提醒三档胶囊)→ 添加提醒按钮。与 App 52/53 的"单卡表单"不同,本页把表单拆成两张卡——FormCard 管"扣什么"(服务信息),RemindCard 管"何时提醒"(提醒规则)。信息录入与规则设置分离成卡,职责边界清晰。
二、四状态声明 + 数据模型
@State name: string = '';
@State amount: string = '';
@State activeCycle: number = 0;
@State remindDays: number = 3;
private cycles: string[] = ['每月', '每季', '每年'];
private remindOptions: number[] = [1, 3, 7];
四个 @State:name(服务名称)、amount(金额)、activeCycle(周期索引,默认 0 = 每月)、remindDays(提醒天数,默认 3)。注意 remindDays 存的是天数数值而非索引——remindOptions 是 [1, 3, 7],选中值直接用天数比较(this.remindDays === d),比索引更语义化。
三、Header:单行标题
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)
}
20 号加粗、safeTop + 56 固定高、文字贴底——系列功能页 Header 统一范式。"添加提醒"是动词短语(动作型标题),暗示"这是一个待完成的操作"。
四、FormCard:四件套服务表单
FormCard() {
Column({ space: 14 }) {
Column({ space: 6 }) {
Text('服务名称').fontSize(13).fontColor(C.textSub).width('100%')
TextInput({ placeholder: '例如:视频VIP会员' })
.backgroundColor(C.cardSoft).borderRadius(D.rSm).height(44)
.onChange((v: string) => { this.name = v; })
}
Column({ space: 6 }) {
Text('扣款金额(元)').fontSize(13).fontColor(C.textSub).width('100%')
TextInput({ placeholder: '0.00' }).type(InputType.Number)
.backgroundColor(C.cardSoft).borderRadius(D.rSm).height(44)
.onChange((v: string) => { this.amount = v; })
}
前两件套:
- 服务名称:
TextInput44 高淡灰底圆角 10,onChange绑定this.name——保存按钮校验的锚点字段(与 App 52 金额、App 53 名称同逻辑:校验最核心的标识字段)。 - 扣款金额:
InputType.Number数字键盘 + 占位符"0.00"——金额字段调起数字键盘减少输入错误,与 App 52 金额输入同款处理。
Column({ space: 6 }) {
Text('扣款周期').fontSize(13).fontColor(C.textSub).width('100%')
Row({ space: 10 }) {
ForEach(this.cycles, (c: string, idx: number) => {
Text(c).fontSize(13)
.fontColor(this.activeCycle === idx ? '#FFFFFF' : C.textSub)
.textAlign(TextAlign.Center).layoutWeight(1).padding({ top: 9, bottom: 9 })
.backgroundColor(this.activeCycle === idx ? C.primary : C.cardSoft).borderRadius(D.rSm)
.onClick(() => { this.activeCycle = idx; })
}, (c: string) => c)
}.width('100%')
}
Column({ space: 6 }) {
Text('扣款日期').fontSize(13).fontColor(C.textSub).width('100%')
TextInput({ placeholder: '每月 1 日' })
.backgroundColor(C.cardSoft).borderRadius(D.rSm).height(44)
}
后两件套:
- 扣款周期 3 等分胶囊:每月/每季/每年——
layoutWeight(1)三等分 +textAlign(TextAlign.Center)居中,选中红底白字(C.primary珊瑚红)。与 App 53 的"保修期限 4 等分"同款布局,选项少(3 项)用等分比换行更高效。 - 扣款日期:
TextInput占位符"每月 1 日"——注意此项无onChange绑定(76 行无状态写入),是四件套中唯一的"展示型输入框",产品化需补绑定或换 DatePicker。

五、RemindCard:提前提醒三档胶囊
RemindCard() {
Column({ space: 12 }) {
Text('提前提醒').fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%')
Row({ space: 10 }) {
ForEach(this.remindOptions, (d: number) => {
Text('提前 ' + d + ' 天').fontSize(12)
.fontColor(this.remindDays === d ? '#FFFFFF' : C.textSub)
.textAlign(TextAlign.Center).layoutWeight(1).padding({ top: 9, bottom: 9 })
.backgroundColor(this.remindDays === d ? C.primary : C.cardSoft).borderRadius(D.rSm)
.onClick(() => { this.remindDays = d; })
}, (d: number) => d.toString())
}.width('100%')
}
.width('100%').padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke })
}
逐点拆解:
- 独立成卡:提醒设置不混在服务表单里,单独一张卡——"扣什么"与"何时提醒"是两类信息,分卡降低认知负荷。
- 天数直存:
ForEach(this.remindOptions, (d: number)——遍历的是[1, 3, 7]数值数组,onClick直接this.remindDays = d存天数(非索引),语义直观。 - 默认 3 天:
remindDays = 3——中位数默认值,与首页临期阈值(daysLeft <= 3)一致,用户添加的提醒与首页告警天然对齐。 - 胶囊文案带前缀:"提前 1 天/提前 3 天/提前 7 天"——文案自带"提前"语境,比光秃秃的数字更易懂。

六、保存按钮:名称校验
Button('添加提醒').fontSize(15).fontColor('#FFFFFF').backgroundColor(C.primary)
.width('100%').height(48).borderRadius(D.rMd)
.onClick(() => { promptAction.showToast({ message: this.name.length > 0 ? '提醒已添加' : '请填写服务名称' }); })
逐点拆解:
- 全宽红色 CTA:
C.primary珊瑚红全宽 48 高——表单页标准 CTA 形态。 - 三元校验:
this.name.length > 0 ? '提醒已添加' : '请填写服务名称'——以名称为校验锚点(服务名称是提醒的标识,没有名字的提醒无法识别)。 - 系列校验锚点对比:App 52 校验金额(票据核心是钱)、App 53 校验名称(商品核心是名)、App 55 校验名称(提醒核心是名)——校验锚点永远指向"没有它记录就没意义"的字段。

七、跨页数据自洽:提醒是续费体系的"录入口"
- 添加页"扣款周期 每月/每季/每年" ↔ 日历页各项的月份分布——周期决定扣款频率,日历时间轴按周期展开(月付项每月出现、年费项一年一次)。
- 添加页"提前提醒 3 天"(默认) ↔ 首页"临期 ≤3 天"——提醒天数 = 告警阈值,用户设 3 天提醒,首页就把 3 天内的扣款标红,录入即生效。
- 添加页"服务名称 + 金额" ↔ 首页列表"名称 + 金额"——保存的新提醒进入首页列表(产品化后
items.push()),录入即展示。 - 添加页"扣款日期" ↔ 日历页"9月1日/9月5日"——录入的日期决定日历时间轴上的位置。
八、系列横向对比:录入页的三种分卡策略
| 录入页 | 代表 App | 分卡策略 | 胶囊布局 | 主题色 |
|---|---|---|---|---|
| 双卡分离 | App 55 续费 | 服务卡 + 提醒卡 | 周期 3 等分 + 提醒 3 等分 | #FF6B6B 珊瑚红 |
| 单卡五件套 | App 53 商品 | 一卡全包 | 分类 5 换行 + 期限 4 等分 | #00A862 生态绿 |
| 上传卡 + 表单 | App 52 票据 | 来源卡 + 表单卡 | 类型/分类双换行 | #0066CC 科技蓝 |
差异点:App 55 的"双卡分离"——把"提醒规则"从服务表单中独立成卡,因为提醒天数是本应用的差异化能力(续费提醒的核心是"何时提醒"而非"记录什么")。App 53 把分类/期限混在一卡(都是商品属性),55 把提醒单列(规则 ≠ 属性),分卡的依据是信息的心智归属。
九、开发者视角:调试与验证技巧
- 天数存值 vs 存索引:
remindDays = 3存天数(this.remindDays === d),activeCycle = 0存索引(this.activeCycle === idx)——同页两种选中态策略,天数选项语义化(值即含义)所以直存数值,周期选项是字符串所以存索引;混用不冲突但要在团队内统一约定。 - 扣款日期无绑定:76 行的
TextInput无onChange——演示漏绑,产品化必须补onChange存状态,否则保存时取不到日期;更优方案是周期选"每月"时用数字选择器选日、选"每年"时用 DatePicker 选月日。 - 金额格式校验:
InputType.Number只限键盘类型——产品化应amount.replace(/[^\d.]/g, '')过滤非法字符并toFixed(2)统一两位小数。 - 默认值联动:周期默认"每月"时日期占位符"每月 1 日"——产品化应让占位符随周期切换变化(选"每年"变"每年 1 月 1 日"),占位符是"活的提示语"。
十、演进方向
| 方向 | 当前状态 | 产品化演进 |
|---|---|---|
| 日期输入 | TextInput 无绑定 | 按周期切换选择器(每月→选日/每年→DatePicker) |
| 金额校验 | Number 键盘 | 非法字符过滤 + 两位小数格式化 |
| 提醒持久化 | Toast 占位 | Preferences 存储 + 通知权限申请 |
| 周期扩展 | 3 档固定 | 支持自定义周期(每 N 天) |
| 保存反馈 | Toast"提醒已添加" | 返回首页刷新 + 新提醒置顶 |
十一、一句话总结
添加页以"双卡分离表单 + 三档提醒胶囊"完成了续费提醒的录入闭环。FormCard 四件套(名称/金额 Number 键盘/周期 3 等分胶囊/日期)+ RemindCard 独立成卡(remindDays 天数直存、默认 3 天与首页临期阈值同源)、名称三元校验——97 行代码,一个"录服务 → 设周期 → 定提醒 → 保存"的提醒建档页,也是"属性与规则分卡"型表单的标准范式。

更多推荐





所有评论(0)