鸿蒙原生应用 ArkTS 表单工程:毕业寄语页的底部固定输入栏与发布校验
鸿蒙原生应用 ArkTS 表单工程:毕业寄语页的底部固定输入栏与发布校验
App 44「校园纪念册」留言页(Func2Tab),主题色
#A29BFE淡紫色(lavender),4 个 Tab 分别为首页(📔)、相册(📸)、留言(💬)、我的(👤)。留言页采用"Header + 寄语流 + 底部输入栏"三区布局——白色单行 Header("毕业寄语"20 号加粗) + 3 条毕业寄语(😊 小林 / 🎈 阿强 / 🌟 小美,每条含 44×44 淡紫圆底 emoji 头像 + 作者 + 时间 + 寄语全文,卡片式) + 底部固定输入栏(42 高圆角 TextInput"写下你的毕业寄语..." + 淡紫"发布"按钮,发布校验"请输入内容"/"留言成功",顶部分隔线 + 安全区)。本篇基于44-memorial-book/entry/src/main/ets/pages/Func2Tab.ets(共 84 行)逐段拆解,附 4 张实机截图。
一、整体结构:三区"Header + 寄语流 + 底部输入栏"布局
留言页是"品牌头部 + 寄语列表 + 固定输入栏"的三区布局——这是系列首个"聊天式"页面(列表 + 底部常驻输入):
build() {
Column() {
this.Header()
Scroll() {
Column({ space: 12 }) {
this.MessageList()
}
.width('100%')
.padding({ left: D.pad, right: D.pad, top: 14, bottom: D.pad + this.safeBottom + 80 })
}
.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
this.InputBar()
}
.width('100%').height('100%').backgroundColor(C.bg)
}
3 块结构:
- Header — 单行品牌头("毕业寄语")
- MessageList — 寄语列表(Scroll 内),底部 padding
safeBottom + 80为输入栏预留空间 - InputBar — 底部固定输入栏(在 Scroll 之外、Column 末尾),常驻屏幕底部
布局关键:InputBar 放在 Scroll 之后(Column 的最下层)——Scroll layoutWeight(1) 占满剩余高度、输入栏固定底部,形成"上列表 + 下输入"的聊天式布局;列表底部 safeBottom + 80 的 padding 确保最后一条寄语不被输入栏遮挡。这是系列中首个"输入常驻"的页面结构,比 App 41/42/43 的"表单在内容区"更接近即时通讯/评论区的交互模型。
二、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 高度、白底、底部对齐——系列二级页统一范式。"毕业寄语"对应首页 Banner"邀请同学一起添加照片和留言"中的"留言"——留言即寄语,是纪念册的情感层(照片记录画面、留言记录心声)。

三、MessageList:毕业寄语流
MessageList() {
Column({ space: 12 }) {
ForEach(this.messages, (m: Message) => {
Row({ space: 12 }) {
Row() { Text(m.emoji).fontSize(22) }
.width(44).height(44).backgroundColor(C.primarySoft).borderRadius(22).justifyContent(FlexAlign.Center)
Column({ space: 6 }) {
Row() {
Text(m.author).fontSize(14).fontWeight(FontWeight.Medium).fontColor(C.text).layoutWeight(1)
Text(m.time).fontSize(11).fontColor(C.textDim)
}.width('100%')
Text(m.content).fontSize(14).fontColor(C.text).lineHeight(22).width('100%')
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
}
.width('100%').padding(14).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke })
}, (m: Message) => m.id.toString())
}.width('100%')
}
3 条寄语(21-25 行):
| emoji | 作者 | 内容 | 时间 |
|---|---|---|---|
| 😊 | 小林 | 四年时光转瞬即逝,愿我们各自安好,前程似锦! | 2天前 |
| 🎈 | 阿强 | 感谢一路有你们,这段友谊我会珍藏一辈子 ❤️ | 3天前 |
| 🌟 | 小美 | 不说再见,因为我们的故事还在继续。江湖再见! | 5天前 |
卡片细节:
- 头像:44×44 淡紫圆底 + 22 号 emoji——作者的头像即情绪符号(😊 温和 / 🎈 欢快 / 🌟 闪亮),比真实头像更贴纪念册的怀旧氛围。
- 头行:作者 14 号 Medium(
layoutWeight(1)占左)+ 时间 11 号浅灰(2天前/3天前/5天前,倒序时间线)。 - 内容:14 号
lineHeight(22)全宽全文——毕业寄语不截断(每条都完整读完),"愿我们各自安好,前程似锦"等文案充满毕业季的感怀。 - 卡片样式:白底圆角 20 + 描边 + 14 内边距,
space: 12间距——与系列卡片语言统一。 - key:
m.id.toString()稳定唯一。
寄语内容分析:三条寄语覆盖毕业情感的不同面向——"前程似锦"(祝福未来)、"珍藏友谊"(感怀过去)、"江湖再见"(洒脱告别),共同构成毕业季的情感全景,也让留言页的文案真实动人。
四、InputBar:底部固定输入栏
InputBar() {
Row({ space: 10 }) {
TextInput({ placeholder: '写下你的毕业寄语...', text: this.input })
.backgroundColor(C.cardSoft).borderRadius(20).height(42).layoutWeight(1)
.onChange((v: string) => { this.input = v; })
Button('发布').fontSize(14).fontColor('#FFFFFF').backgroundColor(C.primary)
.height(42).borderRadius(21)
.onClick(() => { promptAction.showToast({ message: this.input.length > 0 ? '留言成功' : '请输入内容' }); })
}
.width('100%').padding({ left: D.pad, right: D.pad, top: 10, bottom: this.safeBottom + 10 })
.backgroundColor(C.card).border({ width: { top: 1 }, color: C.stroke })
}
技术拆解:
- 圆角胶囊输入框:42 高、圆角 20(全圆角胶囊形)、浅底——
borderRadius(20)在 42 高上形成胶囊,输入框与发布按钮同高同圆角,视觉成对。 - TextInput 受控初值:
text: this.input——显式传入当前输入值,配合onChange写回,形成受控组件(若未来"点击头像预填"等可借此回填,与 App 43 发送页接收人回填同模式)。 - 发布按钮:42 高圆角 21 胶囊、淡紫底白字——与输入框同尺寸并排,右侧固定。
- 分支校验:
this.input.length > 0 ? '留言成功' : '请输入内容'——与 App 41/42/43 同款三元校验,空寄语拦截(寄语必须有点内容才配得上纪念册)。 - 顶部分隔线:
border({ width: { top: 1 }, color: C.stroke })——输入栏与列表区的 1 高浅灰分隔,明确"输入区"边界。 - 安全区:
bottom: this.safeBottom + 10——输入栏沉底时避让底部手势条,保证输入框不被遮挡。 - 新增寄语的链路:
@State messages数组 + 发布成功应unshift新寄语(新寄语置顶)并清空输入——Demo Toast 占位,数据层已就绪。
五、跨页数据自洽:留言页是纪念册的情感层
留言页与首页、我的页的联动:
- "毕业寄语" ↔ 首页 Banner"邀请同学一起添加照片和留言"——Banner 引导的"留言"即本页寄语,照片(相册)+ 留言(寄语)是纪念册的两大内容。
- 留言作者 ↔ 首页纪念册成员——小林/阿强/小美是"计科2022级"班级的同学,与首页"👥 45 人"的成员画像一致。
- 我的页"12 我的留言" ↔ 本页 3 条展示 + 历史留言——12 是个人累计留言数,本页展示最近寄语。
- 新增寄语 ↔ 我的页留言数 +1——发布动作的数据闭环。
六、实机截图与交互演示
本节结合 4 张实机截图,逐张还原留言页的视觉效果与交互过程。
1. 留言页首屏:寄语流 + 底部输入栏
第一张截图是留言页默认首屏:顶部"毕业寄语"标题;下方第一条寄语卡——😊 小林(44×44 淡紫圆底头像)+ "2天前" + "四年时光转瞬即逝,愿我们各自安好,前程似锦!";第二、三条(🎈 阿强 / 🌟 小美)依次排列;屏幕底部是固定输入栏——圆角胶囊 TextInput(占位"写下你的毕业寄语...")+ 淡紫"发布"按钮,顶部分隔线清晰可见。聊天式"上列表 + 下输入"的布局完整呈现。
2. 点击寄语卡:弹出内容 Toast
第二张截图是点击第一条寄语卡后的反馈:弹出"四年时光转瞬即逝,愿我们各自安好,前程似锦!"Toast——onClick 闭包捕获 m.content,点击哪条弹出哪条全文。整卡可点(头像/作者/内容任意区域),产品化后此处进入寄语详情(回复/点赞)。
3. 点击发布:空内容校验 Toast
第三张截图是输入为空时点击底部"发布"按钮的反馈:弹出"请输入内容"Toast——input.length > 0 为 false 走校验分支。空寄语被拦截,用户得到明确引导去输入,寄语流不会被空内容污染。
4. 留言页完整视图:三寄语 + 输入栏
第四张截图是留言页的完整视图:三条寄语全部可见(😊 小林 2天前 / 🎈 阿强 3天前 / 🌟 小美 5天前),时间倒序排列,底部输入栏常驻。列表底部预留了 safeBottom + 80 的空间,最后一条寄语(🌟 小美)不被输入栏遮挡,Scroll 滚动与底部输入互不干扰。
七、扩展思考:评论区与留言的产品设计
留言页是"评论区"的最小实现,其设计可深入:
- 回复与点赞:寄语支持回复(@作者)与点赞(👍)——毕业寄语的互动让"留言"从单向寄语变成同学间的对话,纪念册的留言墙因此"活"起来(App 41 互动页的回复/赞模式可复用)。
- 寄语的时间线:留言按时间倒序(最新在前),也可提供"按届/按年份"归档(2022 级 vs 2023 级寄语)——毕业寄语是分届的情感档案。
- 置顶寄语:班长/班主任寄语可置顶("班主任寄语"固定在顶部)——纪念册的"序言"位,比普通留言更有仪式感。
- 寄语表情包:输入支持插入表情/贴纸——毕业季寄语常用表情强化情感,
TextInput升级为富文本输入。 - 寄语审核:毕业寄语虽以善意为主,仍需敏感词过滤——纪念册是永存的集体档案,内容审核是底线。
八、扩展思考:底部输入栏的交互设计
InputBar 是系列首个底部常驻输入,其交互细节值得展开:
- 键盘弹出:点击 TextInput 弹出软键盘时,输入栏应跟随键盘上移(系统默认)且列表滚动到最底部(让新输入可见)——
Scroll的滚动控制是聊天式页面的关键体验。 - 受控 vs 非受控:
text: this.input+onChange写回是受控组件——若未来实现"点击寄语 @作者"(把 @小林 预填进输入框),受控模式让预填即时生效(App 43 发送页回填同模式)。 - 发布后的滚动:发布成功新寄语
unshift置顶,应自动滚动到顶部让用户看到自己的寄语——滚动联动是发布反馈的一部分。 - 输入栏的占位切换:聚焦时占位"写下你的毕业寄语..."、失焦恢复——
placeholder自动处理,无需额外代码。 - 多行输入:若寄语较长,TextInput 可升级 TextArea(自动增高),但会压缩列表可视区——毕业寄语"短而真挚",单行足够,本页选择合理。
九、开发者视角:留言页的调试与验证技巧
- 底部 padding 与输入栏遮挡:列表
bottom: safeBottom + 80的预留必须大于输入栏高度(约 62)+ 安全区——若改动输入栏高度,记得同步调整 padding,否则最后一条寄语被遮挡(本页 80 预留验证正确)。 - 键盘弹起的列表滚动:点击输入框键盘弹出后,验证列表是否被压缩、能否滚动到最后一条——
Scroll在键盘场景的可用性需真机验证(系列高频坑)。 - 受控 TextInput 的循环:
text: this.input+ onChange 写回同一状态——确认无"显示滞后/输入卡顿"(受控组件正常;若异常,检查是否 onChange 内重复赋值)。 - 校验分支测试:空输入(请输入内容)与有输入(留言成功)两分支——重点测试"先输入再清空"的边界(清空后回拦截分支)。
- 新寄语置顶的实现:若实现发布后
messages.unshift(newMsg),注意@State数组需整体重赋值(this.messages = [newMsg, ...this.messages])才能触发刷新——系列 @State 数组的经典坑。
十、系列横向对比:底部输入栏 vs 表单内输入
App 44 留言页是系列首个"底部固定输入栏",与系列其他输入方式对比可看清选型逻辑:
| 输入形态 | 代表页 | 输入位置 | 场景 |
|---|---|---|---|
| 底部固定栏 | App 44 留言页 | 常驻底部 | 持续评论/留言 |
| 表单卡片内 | App 42 树洞投稿 | 内容区中部 | 一次性提交 |
| 列表内嵌 | App 38 技能发布 | 滚动区 | 短文本填写 |
| 九宫格选择 | App 40 上传页 | 顶部网格 | 多图选择 |
选型逻辑:底部固定输入栏用于"高频、持续"的互动(毕业寄语会反复添加、像发消息),输入栏常驻让用户随时可写;表单内输入用于"低频、一次性"的提交(投稿一次即可),输入区随内容流滚动。输入频率决定输入栏形态——评论区、聊天室用底部固定栏,表单、投稿用内容区表单。
与 App 41 互动页的对比:App 41 互动页是"收到的通知"(被动),本页是"主动写留言"(主动)——同为 💬 但方向相反;本页的底部输入栏若与 App 41 的互动消息结合(留言后可收到"有人留言了你"的通知),即可构成"留言 → 通知 → 回复"的完整社交闭环。

十一、扩展思考:毕业寄语墙的集体情感设计
留言页的寄语是纪念册的情感层,其产品价值值得深入:
- 寄语的仪式感:毕业寄语是"在纪念册上留言"的电子化——实体毕业纪念册上同学手写寄语是最珍贵的部分,电子版应保留这种仪式感(如发布时的"落笔"动画、寄语卡片的手写字体)。
- 寄语的排序:当前时间倒序(最新在前)——也可提供"按作者""按热度"(点赞数)排序;班主任寄语可置顶(纪念册的"序言"),班长寄语次之——排序承载情感优先级。
- 寄语的永久性:毕业寄语是"要留给多年后的自己看"的内容——产品应承诺"纪念册永久保存"(云存储 + 导出备份),这是纪念册产品的信任底线。
- 寄语与照片的呼应:每条寄语可关联照片("毕业合影"旁配"致我们"的寄语)——照片 + 寄语 + 人,构成完整的回忆单元,是纪念册区别于"相册 + 留言分开"的体验升级。
- 多年后的重逢:纪念册可设置"毕业 N 周年解锁"(毕业后第 5 年/10 年推送"该回母校看看了")——时间胶囊式的纪念册,让青春记忆在岁月中持续发酵,是纪念册产品最具想象力的功能。

十二、FAQ 与一句话总结
Q1:留言页为什么是"底部固定输入栏"布局? 留言是"持续参与"的互动(像发消息),输入栏常驻底部让用户随时可写、写完即发——比"表单在内容区"(App 41/42)更接近评论/聊天的心智模型。互动密度决定输入栏形态。
Q2:寄语和首页 Banner 的"留言"是一回事吗? 是——首页 Banner"邀请同学一起添加照片和留言"中的"留言"就是本页的"毕业寄语":照片(相册 Tab)记录画面、留言(本页)记录心声,二者共同构成纪念册的内容。
Q3:发布寄语后能看到吗? Demo 只弹 Toast"留言成功"。产品化后新寄语 unshift 置顶并滚动到顶部,用户立即看到自己的寄语出现在列表——"发布即可见"是留言产品的信任基础。
Q4:为什么寄语不截断(全文展示)? 毕业寄语是情感内容,每条都应完整可读(与 App 41 帖子全文展示同理);消息类的单行摘要(App 41 互动页)是"通知"场景,寄语是"内容"场景,场景决定是否截断。
Q5:输入框支持多行吗? 当前单行 TextInput——毕业寄语"短而真挚"(一句话的祝福),单行足够;若未来支持长留言,升级 TextArea 即可。
一句话总结:留言页以"寄语流 + 底部固定输入栏"完成了纪念册的情感层,是系列首个聊天式布局(列表 + 常驻输入)。受控 TextInput + 发布校验、"safeBottom + 80"的输入栏避让、emoji 头像即作者情绪、三条寄语覆盖"祝福/感怀/告别"的毕业情感全景——84 行代码,一个让同学留下心声的毕业寄语墙,也是评论区类页面的标准参考。

十三、开发者视角:留言页的调试与验证技巧
- 底部 padding 与输入栏遮挡:列表
bottom: safeBottom + 80的预留必须大于输入栏总高(约 62)+ 安全区——若改动输入栏高度(如加 emoji 按钮),同步调整 padding,否则最后一条寄语被遮挡(本页 80 预留验证正确,改动后需回归)。 - 键盘弹起的列表可用性:点击 TextInput 键盘弹出后,验证列表是否被压缩、能否滚动到最后一条、输入栏是否跟随键盘上移——聊天式页面的键盘适配需真机验证(系列高频坑)。
- 受控 TextInput 的显示滞后:
text: this.input+ onChange 写回——确认输入无卡顿、显示无滞后;若异常,检查是否 onChange 内重复赋值造成死循环。 - 校验分支测试:空输入(请输入内容)与有输入(留言成功)两分支——重点测试"先输入再清空"的边界(清空后应回拦截分支)。
- 新寄语置顶的实现:发布后
this.messages = [newMsg, ...this.messages](整体重赋值触发刷新)——不能push(原地修改不触发 @State),这是系列 @State 数组的经典坑。
十四、FAQ 与一句话总结
Q6:寄语支持点赞和回复吗? Demo 未实现。产品化后寄语卡加"👍 点赞"与"回复"按钮(App 41 互动页模式),回复形成"寄语 → 回复"的对话链——毕业寄语的互动让留言墙"活"起来。
Q7:班主任寄语能置顶吗? 可以——Message 加 isPinned 字段,置顶寄语固定在列表顶部(类似"置顶消息")——纪念册的"序言"位,比普通留言更有仪式感。
Q8:寄语会永久保存吗? 纪念册的产品承诺是"永久保存"——寄语云存储 + 可导出(PDF/电子书),多年后仍可回看;这是纪念册产品(含留言)的信任底线。
Q9:输入框支持表情吗? Demo 纯文本。产品化可在输入栏加"😊"按钮插入 emoji(TextInput 支持 emoji 输入)——毕业寄语常配表情强化情感(现有寄语已有 ❤️/😊)。
Q10:发布寄语后会显示作者的真实身份吗? 当前寄语带作者名(小林/阿强/小美)——纪念册是实名集体产品(不同于 App 41/42 匿名),作者实名让寄语"有人认领",多年后"看到小林写的"更有回忆价值。这些 FAQ 与前面的拆解共同构成本页的完整解析。
最后从验收视角确认:四张实机截图覆盖了首屏(寄语流+底部输入栏)、寄语点击(内容 Toast)、空内容发布(请输入内容 Toast)、完整视图(三寄语+输入栏)四个状态,底部固定输入栏、受控 TextInput、发布校验、safeBottom+80 的输入栏避让均验证正常。寄语作者(小林/阿强/小美)为班级成员。整页 84 行代码完成"寄语流 + 常驻输入"的聊天式留言页,验收通过,可作为评论区/留言类页面的标准参考。
补充一处细节:留言页的寄语卡与首页纪念册卡、相册页照片卡共用"白底圆角描边"的卡片语言,但头像区(44×44 圆形淡紫底)比纪念册封面(80×90 直角图块)更"圆"——因为寄语是"人说的话",圆形头像强调"人"的存在(像聊天头像),直角图块强调"物的封面"(像书本封面),"圆即人、方即物"的形态语义在三个页面间悄然统一。而底部输入栏的胶囊圆角(输入框 20、按钮 21)则是最"圆"的元素——输入是最亲近的互动,用最圆润的形态降低"开口说话"的心理门槛,与毕业寄语的温情场景相得益彰。这些"圆方对照"的细节虽小,却让留言页在功能之外多了一层"人味",84 行代码的聊天式布局因此显得亲切而不冰冷。

更多推荐





所有评论(0)