ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HarmonyOS 应用 · 班费管理收支页深度解析:四状态表单与 Flex 分类胶囊

HarmonyOS 应用 · 班费管理收支页深度解析:四状态表单与 Flex 分类胶囊 HarmonyOS 应用 · 班费管理收支页深度解析四状态表单与 Flex 分类胶囊项目编号47-class-fund 技术栈HarmonyOS ArkTS · ArkUI 声明式 UI · Stage 模型 本篇页面收支页Func1Tab.ets108 行 系列导航一首页 ·二收支· 三成员 · 四统计一、四 State 驱动的表单状态机State isIncome: boolean false; State amount: string ; State remark: string ; State activeCat: number 0; private incomeCats: string[] [班费收缴, 活动结余, 其他收入]; private expenseCats: string[] [活动采购, 物资费用, 团建费用, 奖品支出, 其他支出]; private getCats(): string[] { return this.isIncome ? this.incomeCats : this.expenseCats; }收支页有四个StateisIncome支出/收入切换、amount金额输入、remark备注输入、activeCat分类选中索引。getCats()是派生方法——根据isIncome返回对应分类数组支出 5 个、收入 3 个。isIncome变化时getCats()返回不同数组分类列表即时刷新。二、页面骨架TypeSwitch AmountCard CatCard RemarkCard Buttonbuild() { Column() { this.Header() Scroll() { Column({ space: 16 }) { this.TypeSwitch() this.AmountCard() this.CatCard() this.RemarkCard() Button(保存记录).fontSize(15).fontColor(#FFFFFF).backgroundColor(C.primary) .width(100%).height(48).borderRadius(D.rMd) .onClick(() { promptAction.showToast({ message: this.amount.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) }Header 在 Scroll 外固定Scroll 内五块TypeSwitch类型切换 AmountCard金额 CatCard分类 RemarkCard备注 Button保存。Button直接内联在 build 中未抽 Builder——因为它是单行组件无需复用。保存按钮的onClick做了空值校验amount.length 0才提示记录已保存否则提示请输入金额。三、TypeSwitchisIncome 驱动的红绿双选Builder TypeSwitch() { Row() { Text(支出).fontSize(14) .fontColor(!this.isIncome ? #FFFFFF : C.textSub) .textAlign(TextAlign.Center).layoutWeight(1).padding({ top: 11, bottom: 11 }) .backgroundColor(!this.isIncome ? C.danger : Color.Transparent).borderRadius(D.rSm) .onClick(() { this.isIncome false; this.activeCat 0; }) Text(收入).fontSize(14) .fontColor(this.isIncome ? #FFFFFF : C.textSub) .textAlign(TextAlign.Center).layoutWeight(1).padding({ top: 11, bottom: 11 }) .backgroundColor(this.isIncome ? C.ok : Color.Transparent).borderRadius(D.rSm) .onClick(() { this.isIncome true; this.activeCat 0; }) } .width(100%).padding(4).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) }isIncome驱动红绿双选——支出用C.danger红色、收入用C.ok绿色// 支出选中红底白字 .backgroundColor(!this.isIncome ? C.danger : Color.Transparent) // 收入选中绿底白字 .backgroundColor(this.isIncome ? C.ok : Color.Transparent)点击支出设isIncome falseactiveCat 0点击收入设isIncome trueactiveCat 0——切换类型时重置分类选中索引避免越界支出 5 项 → 收入 3 项索引 4 会越界。四、AmountCard¥ 前缀 TextInput 数字输入Builder AmountCard() { Row({ space: 6 }) { Text(¥).fontSize(28).fontWeight(FontWeight.Bold).fontColor(C.text) TextInput({ placeholder: 0.00 }).type(InputType.Number) .backgroundColor(Color.Transparent).borderRadius(0).height(56) .fontSize(28).layoutWeight(1) .onChange((v: string) { this.amount v; }) } .width(100%).padding({ left: 16, right: 16 }).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke }) }28 号 ¥ 前缀 28 号TextInputtype(InputType.Number)限制数字键盘——金额输入只允许数字。backgroundColor(Color.Transparent)让输入框透明融入卡片。onChange写入this.amount触发State刷新。五、CatCardFlex wrap 自动换行分类胶囊Builder CatCard() { Column({ space: 10 }) { Text(分类).fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.text).width(100%) Flex({ wrap: FlexWrap.Wrap }) { ForEach(this.getCats(), (c: string, idx: number) { Text(c).fontSize(12) .fontColor(this.activeCat idx ? #FFFFFF : C.textSub) .padding({ left: 14, right: 14, top: 7, bottom: 7 }) .backgroundColor(this.activeCat idx ? C.primary : C.cardSoft).borderRadius(14) .margin({ right: 10, bottom: 10 }) .onClick(() { this.activeCat idx; }) }, (c: string, idx: number) c idx) }.width(100%) } .width(100%).padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke }) }Flex({ wrap: FlexWrap.Wrap })是本页特色——自动换行的弹性布局。支出有 5 个分类一行放不下FlexWrap.Wrap让胶囊自动换行。每个胶囊borderRadius(14)全圆角 margin({ right: 10, bottom: 10 })间距。activeCat驱动选中态——字色与底色两路分支// 选中绿底白字 .backgroundColor(this.activeCat idx ? C.primary : C.cardSoft) // 未选浅灰底灰字 .fontColor(this.activeCat idx ? #FFFFFF : C.textSub)getCats()根据isIncome返回不同数组——切换类型时分类列表整体替换。六、RemarkCard备注输入Builder RemarkCard() { Column({ space: 10 }) { Text(备注).fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.text).width(100%) TextInput({ placeholder: 添加备注说明 }) .backgroundColor(C.cardSoft).borderRadius(D.rSm).height(44) .onChange((v: string) { this.remark v; }) } .width(100%).padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke }) }14 号标题 TextInput备注。与 AmountCard 不同备注输入框用C.cardSoft浅灰底 borderRadius(D.rSm)小圆角——视觉权重低于金额输入符合金额是主信息、备注是辅助的层级关系。七、表单状态联动链路四个State形成联动链路TypeSwitch 点击 → isIncome 翻转 → getCats() 返回新数组 → CatCard 胶囊列表刷新 → activeCat 重置为 0 → 选中态回到第一个 AmountCard 输入 → amount 更新 → 保存按钮校验 amount.length 0 CatCard 点击 → activeCat 更新 → 选中胶囊高亮转移 RemarkCard 输入 → remark 更新 → 随记录保存isIncome是链路起点——它的变化同时影响 TypeSwitch 的红绿选中态、CatCard 的分类列表、activeCat 的重置一次点击触发三处刷新。八、可演进方向方向现状改法收益保存写入Toast 模拟写入 records 数组 余额重算记录真实保存金额校验仅非空正数 两位小数 上限金额格式合法分类管理写死数组服务端配置 自定义分类分类可扩展日期选择无DatePicker 选日期记录日期可调表单重置无保存后清空 amount/remark/activeCat连续录入收支页是班费管理的录入入口——四State驱动的表单状态机、isIncome红绿双选、Flex wrap自动换行分类胶囊。从 TypeSwitch 的类型联动到保存按钮的空值校验每一层都有明确的职责边界。系列导航一首页 ·二收支· 三成员 · 四统计
返回列表