HarmonyOS7 弹性布局处理异常文案:ArkUI/ArkTS 实战拆解
文章目录
前言
异常文案是检验布局韧性的最好材料。标题一长、按钮一多、屏幕一窄,平时看起来很整齐的卡片就可能把操作区挤没。
这篇单独聊 长标题卡片 这个场景。重点不是堆 API,而是用弹性布局保证极端文案、按钮和状态标签不会互相挤压。
为什么布局一碰到长文案就容易露馅
因为正常文案太容易把页面骗过去了。四五个字的标题、短短一行说明、两个字的按钮,看起来怎么排都顺。
可一旦换成真实业务里的异常标题、设备编号、英文长串和多语言翻译,很多原本“挺整齐”的布局马上就会露底:按钮被挤扁,标签换行,卡片高度失控。
所以这篇文章真正想解决的,不是让页面在理想文案下好看,而是让它在最麻烦的文案下也别崩。
场景:消息中心的异常通知卡片
真实业务里的文案不会总是四个字。订单异常、设备离线、地址识别失败、活动审核驳回,这些标题经常又长又具体。消息中心如果只按短文案设计,最常见的问题就是标题把按钮挤没,状态标签换行变形,或者整张卡片高度突然失控。
我做这类卡片时会先保护关键操作:按钮必须可点,状态必须可读,主文案可以伸缩和截断。也就是说,布局不是让所有内容都完整显示,而是在小屏和长文案下保住信息优先级。
UI 稳不稳,要看最长文案、最小屏幕、最大字号下会不会崩。
布局策略
| 元素 | 布局策略 | 原因 |
|---|---|---|
| 状态标签 | 固定内容宽度,不参与伸缩 | 避免“异常”被压变形 |
| 主标题 | layoutWeight(1) + maxLines |
吸收剩余空间 |
| 操作按钮 | 固定宽高 | 保证可点击区域 |
| 辅助说明 | 单独放下一行 | 避免和按钮抢空间 |
| 时间文案 | 弱化显示 | 信息重要性低于标题 |
实操步骤
- 先确定卡片里谁必须完整显示,通常是状态和按钮。
- 主标题放在可伸缩区域,使用
layoutWeight(1)。 - 长文案设置
maxLines和textOverflow,不要撑破卡片。 - 辅助说明放到下一行,不要和操作按钮同排硬挤。
- 用短文案、长文案、无空格长串、较大字号都测一遍。
- 列表 key 使用业务 id,避免异常通知刷新时错位。
先把卡片里谁不能退让想清楚
做异常通知卡片时,先别急着调 Row 和 Column。更重要的是先判断:这一排里谁必须保住,谁可以让位。大多数情况下,操作按钮必须可点,状态标签必须可读,标题可以适当截断,辅助说明可以放到下一行。
你先把这个优先级排清楚,再去看 layoutWeight(1)、固定宽度和换行策略,就会明白这些 API 不是随便拼出来的,而是在帮你执行“谁保留、谁让位”这件事。对小白来说,这一步能明显减少布局一乱就只会反复试数值的情况。
完整示例:可承受长文案的通知列表
interface NoticeItem {
id: number
title: string
desc: string
action: string
level: string
time: string
}
@Entry
@Component
struct FlexibleTextPage {
private notices: NoticeItem[] = [
{ id: 1, title: '订单已完成', desc: '可查看订单详情和发票信息。', action: '查看', level: 'normal', time: '09:20' },
{ id: 2, title: '由于收货地址包含无法识别的楼栋信息,当前配送任务需要用户重新确认详细地址', desc: '请在 24 小时内处理,否则配送任务会自动暂停。', action: '处理', level: 'warn', time: '10:48' },
{ id: 3, title: 'DEVICE-ALPHA-2026-SUPER-LONG-NAME-NEEDS-CHECK', desc: '设备名称来自外部系统,可能没有自然断句。', action: '检查', level: 'error', time: '11:03' }
]
private levelText(level: string): string {
if (level === 'error') {
return '错误'
}
if (level === 'warn') {
return '异常'
}
return '正常'
}
private levelColor(level: string): string {
if (level === 'error') {
return '#B42318'
}
if (level === 'warn') {
return '#D92D20'
}
return '#0A7F3F'
}
@Builder
NoticeCard(item: NoticeItem) {
Column({ space: 8 }) {
Row({ space: 10 }) {
Text(this.levelText(item.level))
.fontSize(12)
.fontColor('#FFFFFF')
.padding({ left: 6, right: 6, top: 3, bottom: 3 })
.backgroundColor(this.levelColor(item.level))
.borderRadius(4)
Text(item.title)
.fontSize(15)
.fontColor('#222222')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
Button(item.action)
.width(64)
.height(32)
.fontSize(12)
}.width('100%')
Row() {
Text(item.desc)
.fontSize(13)
.fontColor('#666666')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.layoutWeight(1)
Text(item.time)
.fontSize(12)
.fontColor('#999999')
.margin({ left: 8 })
}.width('100%')
}
.alignItems(HorizontalAlign.Start)
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)
}
build() {
Column({ space: 12 }) {
Text('异常文案布局')
.fontSize(22)
.fontWeight(FontWeight.Bold)
ForEach(this.notices, (item: NoticeItem) => {
this.NoticeCard(item)
}, (item: NoticeItem) => item.id.toString())
}
.padding(16)
.backgroundColor('#F5F7FA')
.height('100%')
}
}
把关键代码一段段拆开
标题使用 layoutWeight(1),表示它占用标签和按钮之外的剩余空间。这样按钮不会被长标题挤出屏幕,标题也不会和操作区重叠。
maxLines(2) 比单行截断更适合异常通知。异常文案通常需要多一点上下文,两行能让用户看懂大概原因;超过两行再省略,避免卡片失控。
辅助说明放在第二行,和时间文案同排。主标题那一排已经有状态标签和按钮,不应该再塞更多信息。信息层级清楚了,弹性布局才有发挥空间。
容易踩坑的点
- 标题不设置最大行数,长文案把卡片撑到半屏。
- 按钮没有固定宽度,被标题挤到只剩几个像素。
- 状态标签参与伸缩,文字被压缩或换行。
- 只测试中文短句,没有测试英文长串、设备编号、异常码。
- 辅助说明和按钮放在同一行,窄屏下互相抢空间。
优化建议
长文案不是单纯截断就完事。如果异常原因很重要,可以点击卡片进入详情页展示完整内容;列表里只保留摘要和动作。这样列表保持可扫读,详情页承接完整解释。
还要考虑字号放大和多语言。英文、数字、设备编号不一定有自然断点,布局压力比中文更大。做国际化或系统字号适配时,最好准备一组极端数据作为 UI 回归用例。
如果团队里经常有人因为改文案把布局改崩,我会把这些极端样例直接做成假数据常驻在开发环境里。这样每次改样式时都能顺手看到最坏情况,而不是等测试阶段才发现按钮已经被长标题挤没。
异常文案要按信息优先级让位
弹性布局不是让所有内容都完整显示,而是在空间不够时保住最重要的信息。异常通知里,状态标签和操作按钮通常必须可见,标题可以两行省略,辅助说明可以弱化或交给详情页承接。
示例让标题使用 layoutWeight(1) 吸收剩余空间,按钮保持固定宽高,状态标签不参与伸缩。这样长标题不会把按钮挤没,用户仍然能完成处理动作。
写在最后
测试时不要只放正常中文短句。英文长串、设备编号、异常码、系统字号放大、多语言翻译都会给布局制造压力。能扛住这些异常文案,卡片才算真正稳定。
更多推荐


所有评论(0)