鸿蒙原生应用 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 块结构:

  1. Header — 单行品牌头("毕业寄语")
  2. MessageList — 寄语列表(Scroll 内),底部 padding safeBottom + 80 为输入栏预留空间
  3. InputBar — 底部固定输入栏(在 Scroll 之外、Column 末尾),常驻屏幕底部

布局关键:InputBar 放在 Scroll 之后(Column 的最下层)——Scroll layoutWeight(1) 占满剩余高度、输入栏固定底部,形成"上列表 + 下输入"的聊天式布局;列表底部 safeBottom + 80 的 padding 确保最后一条寄语不被输入栏遮挡。这是系列中首个"输入常驻"的页面结构,比 App 41/42/43 的"表单在内容区"更接近即时通讯/评论区的交互模型。

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

二、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"邀请同学一起添加照片和留言"中的"留言"——留言即寄语,是纪念册的情感层(照片记录画面、留言记录心声)。

44 留言页首屏

三、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天前

卡片细节:

  1. 头像:44×44 淡紫圆底 + 22 号 emoji——作者的头像即情绪符号(😊 温和 / 🎈 欢快 / 🌟 闪亮),比真实头像更贴纪念册的怀旧氛围。
  2. 头行:作者 14 号 Medium(layoutWeight(1) 占左)+ 时间 11 号浅灰(2天前/3天前/5天前,倒序时间线)。
  3. 内容:14 号 lineHeight(22) 全宽全文——毕业寄语不截断(每条都完整读完),"愿我们各自安好,前程似锦"等文案充满毕业季的感怀。
  4. 卡片样式:白底圆角 20 + 描边 + 14 内边距,space: 12 间距——与系列卡片语言统一。
  5. 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 })
}

技术拆解:

  1. 圆角胶囊输入框:42 高、圆角 20(全圆角胶囊形)、浅底——borderRadius(20) 在 42 高上形成胶囊,输入框与发布按钮同高同圆角,视觉成对。
  2. TextInput 受控初值:text: this.input——显式传入当前输入值,配合 onChange 写回,形成受控组件(若未来"点击头像预填"等可借此回填,与 App 43 发送页接收人回填同模式)。
  3. 发布按钮:42 高圆角 21 胶囊、淡紫底白字——与输入框同尺寸并排,右侧固定。
  4. 分支校验:this.input.length > 0 ? '留言成功' : '请输入内容'——与 App 41/42/43 同款三元校验,空寄语拦截(寄语必须有点内容才配得上纪念册)。
  5. 顶部分隔线:border({ width: { top: 1 }, color: C.stroke })——输入栏与列表区的 1 高浅灰分隔,明确"输入区"边界。
  6. 安全区:bottom: this.safeBottom + 10——输入栏沉底时避让底部手势条,保证输入框不被遮挡。
  7. 新增寄语的链路:@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 滚动与底部输入互不干扰。

七、扩展思考:评论区与留言的产品设计

留言页是"评论区"的最小实现,其设计可深入:

  1. 回复与点赞:寄语支持回复(@作者)与点赞(👍)——毕业寄语的互动让"留言"从单向寄语变成同学间的对话,纪念册的留言墙因此"活"起来(App 41 互动页的回复/赞模式可复用)。
  2. 寄语的时间线:留言按时间倒序(最新在前),也可提供"按届/按年份"归档(2022 级 vs 2023 级寄语)——毕业寄语是分届的情感档案。
  3. 置顶寄语:班长/班主任寄语可置顶("班主任寄语"固定在顶部)——纪念册的"序言"位,比普通留言更有仪式感。
  4. 寄语表情包:输入支持插入表情/贴纸——毕业季寄语常用表情强化情感,TextInput 升级为富文本输入。
  5. 寄语审核:毕业寄语虽以善意为主,仍需敏感词过滤——纪念册是永存的集体档案,内容审核是底线。

八、扩展思考:底部输入栏的交互设计

InputBar 是系列首个底部常驻输入,其交互细节值得展开:

  1. 键盘弹出:点击 TextInput 弹出软键盘时,输入栏应跟随键盘上移(系统默认)且列表滚动到最底部(让新输入可见)——Scroll 的滚动控制是聊天式页面的关键体验。
  2. 受控 vs 非受控:text: this.input + onChange 写回是受控组件——若未来实现"点击寄语 @作者"(把 @小林 预填进输入框),受控模式让预填即时生效(App 43 发送页回填同模式)。
  3. 发布后的滚动:发布成功新寄语 unshift 置顶,应自动滚动到顶部让用户看到自己的寄语——滚动联动是发布反馈的一部分。
  4. 输入栏的占位切换:聚焦时占位"写下你的毕业寄语..."、失焦恢复——placeholder 自动处理,无需额外代码。
  5. 多行输入:若寄语较长,TextInput 可升级 TextArea(自动增高),但会压缩列表可视区——毕业寄语"短而真挚",单行足够,本页选择合理。

九、开发者视角:留言页的调试与验证技巧

  1. 底部 padding 与输入栏遮挡:列表 bottom: safeBottom + 80 的预留必须大于输入栏高度(约 62)+ 安全区——若改动输入栏高度,记得同步调整 padding,否则最后一条寄语被遮挡(本页 80 预留验证正确)。
  2. 键盘弹起的列表滚动:点击输入框键盘弹出后,验证列表是否被压缩、能否滚动到最后一条——Scroll 在键盘场景的可用性需真机验证(系列高频坑)。
  3. 受控 TextInput 的循环:text: this.input + onChange 写回同一状态——确认无"显示滞后/输入卡顿"(受控组件正常;若异常,检查是否 onChange 内重复赋值)。
  4. 校验分支测试:空输入(请输入内容)与有输入(留言成功)两分支——重点测试"先输入再清空"的边界(清空后回拦截分支)。
  5. 新寄语置顶的实现:若实现发布后 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 的互动消息结合(留言后可收到"有人留言了你"的通知),即可构成"留言 → 通知 → 回复"的完整社交闭环。

44 留言页完整视图

十一、扩展思考:毕业寄语墙的集体情感设计

留言页的寄语是纪念册的情感层,其产品价值值得深入:

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

44 留言页寄语 Toast

十二、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 行代码,一个让同学留下心声的毕业寄语墙,也是评论区类页面的标准参考。

44 留言页校验 Toast

十三、开发者视角:留言页的调试与验证技巧

  1. 底部 padding 与输入栏遮挡:列表 bottom: safeBottom + 80 的预留必须大于输入栏总高(约 62)+ 安全区——若改动输入栏高度(如加 emoji 按钮),同步调整 padding,否则最后一条寄语被遮挡(本页 80 预留验证正确,改动后需回归)。
  2. 键盘弹起的列表可用性:点击 TextInput 键盘弹出后,验证列表是否被压缩、能否滚动到最后一条、输入栏是否跟随键盘上移——聊天式页面的键盘适配需真机验证(系列高频坑)。
  3. 受控 TextInput 的显示滞后:text: this.input + onChange 写回——确认输入无卡顿、显示无滞后;若异常,检查是否 onChange 内重复赋值造成死循环。
  4. 校验分支测试:空输入(请输入内容)与有输入(留言成功)两分支——重点测试"先输入再清空"的边界(清空后应回拦截分支)。
  5. 新寄语置顶的实现:发布后 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 行代码的聊天式布局因此显得亲切而不冰冷。

Logo

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

更多推荐