ArkUI Text:文字排顺了,页面像换了个设计师
ArkUI Text:文字排顺了,页面像换了个设计师
今天我们继续把 Text 这篇补完整:不只让文字显示出来,还要让一句话里的重点、小标签、小图标都能自然地排在一起。
页面里最常见的问题不是“没有文字”,而是文字都长一个样。标题不像标题,说明太抢眼,关键字没有重点,小图标还被单独塞进 Row 里,最后越写越乱。
这篇我们只盯文本本身。Text 管整段文字,Span 管局部文字,ImageSpan 管夹在文字里的图片。先把这三个关系捋清楚,后面写列表、卡片、表单时会省很多事。
参考文档:
- https://developer.huawei.cn/consumer/cn/doc/harmonyos-guides/arkts-common-components-text-display
- https://developer.huawei.cn/consumer/cn/doc/harmonyos-guides/arkts-text-image-layout
- https://developer.huawei.cn/consumer/cn/doc/harmonyos-guides/arkui
- https://developer.huawei.cn/consumer/cn/doc/harmonyos-guides/arkts-ui-development
先把页面骨架放下
案例页面只有一个文件:
entry/src/main/ets/pages/arkUI/basic/ArkUITextDemo.ets
开头还是老规矩:一个组件名,一个标题,再用一段轻一点的说明把范围讲清楚。
Text('ArkUI Text')
.width('100%')
.fontSize(24)
.fontWeight(700)
.fontColor('#0F172A')
Text('今天我们只做一件事:把文字层级调顺。先看字号、颜色、行高、Span、ImageSpan 和截断,别急着往页面里塞更多组件。')
.width('100%')
.fontSize(14)
.fontColor('#64748B')
.lineHeight(22)
说明文字别写得太黑。它只是帮读者知道下面要看什么,不应该抢走标题的注意力。
字号先把身份分出来
正文和标题不要用同一套字号。能显示是一回事,能不能一眼分清层级是另一回事。
Text('普通正文适合用 14 到 16 的字号,颜色不要太黑。')
.width('100%')
.fontSize(15)
.fontColor('#475569')
.lineHeight(24)
Text('标题文本要有层级')
.width('100%')
.fontSize(20)
.fontWeight(700)
.fontColor('#0F172A')
我一般会先把正文压住,别让它黑得像标题。标题再加粗,层级自然就出来了。
颜色别一把梭
同样是文字,主信息、补充说明、风险提示,最好别都一个颜色。
Text('主信息:用户第一眼应该看到这一句')
.fontSize(16)
.fontWeight(700)
.fontColor('#1D4ED8')
Text('次信息:补充说明放轻一点,别和主信息抢注意力')
.fontSize(14)
.fontColor('#64748B')
Text('警示信息:颜色可以提醒风险,但不要把整页都染红')
.fontSize(14)
.fontWeight(600)
.fontColor('#B91C1C')
红色不是不能用,但别一出问题就满屏红。只把真正需要提醒的那句标出来就够了。
Span 负责一句话里的重点
如果只是某几个字需要加粗、换色、加背景,不用拆成好几个 Text。我们可以在 Text() 里放多个 Span。
Text() {
Span('同一行文字里,')
.fontSize(15)
.fontColor('#334155')
Span('真正要强调的词')
.fontSize(15)
.fontWeight(700)
.fontColor('#2563EB')
.textBackgroundStyle({ color: '#DBEAFE', radius: 4 })
Span(' 可以用 Span 单独处理,不用拆成好几个 Text。')
.fontSize(15)
.fontColor('#334155')
}
.width('100%')
.lineHeight(24)
这段代码的重点是:外层 Text() 管这一整行,里面每个 Span 管自己的样式。这样文字还在同一个排版上下文里,换行、行高、对齐都更自然。
小标签也适合用 Span。比如我们在句子前面放一个 NEW:
Text() {
Span('NEW')
.fontSize(12)
.fontWeight(700)
.fontColor('#C2410C')
.letterSpacing(1)
.textCase(TextCase.UpperCase)
Span(' 这种标签可以贴在句子开头,提示用户这是新内容。')
.fontSize(15)
.fontColor('#475569')
}
.width('100%')
.lineHeight(24)
这里我们故意没有把它做成按钮或徽章组件,因为它只是文字的一部分。用 Span 就够了,简单,也不容易把布局带偏。
ImageSpan 负责文字里的小图标
有些图标天然应该跟文字走,比如会员标识、状态标记、说明里的小图。这个时候用 ImageSpan 比额外写一个 Row 更轻。
Text() {
ImageSpan($r('app.media.startIcon'))
.width(18)
.height(18)
.verticalAlign(ImageSpanAlignment.CENTER)
.objectFit(ImageFit.Contain)
Span(' 会员标识可以跟文字在同一行,不用额外写 Row 去拼。')
.fontSize(15)
.fontColor('#334155')
}
.width('100%')
.lineHeight(26)
verticalAlign(ImageSpanAlignment.CENTER) 这句很关键。图片和文字默认不一定刚好在视觉中心,稍微一偏就会显得粗糙。
SVG 资源也可以放进 ImageSpan:
Text() {
Span('支持 ')
.fontSize(15)
.fontColor('#475569')
ImageSpan($r('app.media.icon_huawei'))
.width(18)
.height(18)
.verticalAlign(ImageSpanAlignment.CENTER)
.objectFit(ImageFit.Contain)
Span(' 这种小图标跟文字自然对齐,适合放在说明、标签或状态文案里。')
.fontSize(15)
.fontColor('#475569')
}
.width('100%')
.lineHeight(26)
这类图文混排不适合搞太复杂。图片只做辅助,尺寸别太大,文字才是主角。
长句别放任它乱长
列表摘要、商品描述、卡片标题,都可能遇到长文本。我们给它最多两行,超出就省略。
Text('这是一段故意写长的文字,用来展示 maxLines 和 textOverflow。真实业务里,卡片标题、列表摘要、商品描述都可能需要截断,否则一个长句就能把整个布局撑乱。')
.width('100%')
.fontSize(15)
.fontColor('#334155')
.lineHeight(24)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
这块很实用。你只要做过列表,大概率都被长标题折磨过。
看效果时盯这几处
打开案例页面后,别只看“有没有显示”。我们重点看这几件事:
- 正文和标题有没有拉开层级。
- 主信息、次信息、警示信息有没有各站各的位置。
Span的强调词是不是还在同一行文字节奏里。ImageSpan的小图标有没有和文字居中对齐。- 长段落读起来挤不挤。
- 最后一段是不是最多两行,后面带省略号。
你在 DevEco Studio 里打开案例页面看就行,不用急着改业务代码,先观察文字层级有没有舒服一点。
顺手改两处
可以把 Span('真正要强调的词') 的背景色换成浅绿色,看看强调感会不会变弱。
也可以把 ImageSpan 的尺寸从 18 改成 14 或 22。你会很直观地看到:图标只要大一点,就可能从“辅助信息”变成“抢戏信息”。
你平时写说明文案时,更常遇到哪种麻烦:一句话里几个字要强调,还是图标和文字总是对不齐?可以直接说说你的场景。
完整示例代码
文件位置:entry/src/main/ets/pages/arkUI/basic/ArkUITextDemo.ets
@Entry
@Component
struct ArkUITextDemo {
@Builder
sectionTitle(title: string) {
Text(title)
.width('100%')
.fontSize(15)
.fontWeight(700)
.fontColor('#334155')
}
build() {
Scroll() {
Column({ space: 18 }) {
Text('ArkUI Text')
.width('100%')
.fontSize(24)
.fontWeight(700)
.fontColor('#0F172A')
Text('文字不是能显示就够了')
.width('100%')
.fontSize(22)
.fontWeight(700)
.fontColor('#111827')
Text('今天我们只做一件事:把文字层级调顺。先看字号、颜色、行高、Span、ImageSpan 和截断,别急着往页面里塞更多组件。')
.width('100%')
.fontSize(14)
.fontColor('#64748B')
.lineHeight(22)
Column({ space: 12 }) {
this.sectionTitle('基础文本')
Text('普通正文适合用 14 到 16 的字号,颜色不要太黑。')
.width('100%')
.fontSize(15)
.fontColor('#475569')
.lineHeight(24)
Text('标题文本要有层级')
.width('100%')
.fontSize(20)
.fontWeight(700)
.fontColor('#0F172A')
}
.width('100%')
.padding(16)
.backgroundColor('#F8FAFC')
.borderRadius(8)
Column({ space: 12 }) {
this.sectionTitle('颜色和强调')
Text('主信息:用户第一眼应该看到这一句')
.width('100%')
.fontSize(16)
.fontWeight(700)
.fontColor('#1D4ED8')
Text('次信息:补充说明放轻一点,别和主信息抢注意力')
.width('100%')
.fontSize(14)
.fontColor('#64748B')
Text('警示信息:颜色可以提醒风险,但不要把整页都染红')
.width('100%')
.fontSize(14)
.fontWeight(600)
.fontColor('#B91C1C')
}
.width('100%')
.padding(16)
.backgroundColor('#FFFFFF')
.border({ width: 1, color: '#E2E8F0' })
.borderRadius(8)
Column({ space: 12 }) {
this.sectionTitle('Span 局部强调')
Text() {
Span('同一行文字里,')
.fontSize(15)
.fontColor('#334155')
Span('真正要强调的词')
.fontSize(15)
.fontWeight(700)
.fontColor('#2563EB')
.textBackgroundStyle({ color: '#DBEAFE', radius: 4 })
Span(' 可以用 Span 单独处理,不用拆成好几个 Text。')
.fontSize(15)
.fontColor('#334155')
}
.width('100%')
.lineHeight(24)
Text() {
Span('NEW')
.fontSize(12)
.fontWeight(700)
.fontColor('#C2410C')
.letterSpacing(1)
.textCase(TextCase.UpperCase)
Span(' 这种标签可以贴在句子开头,提示用户这是新内容。')
.fontSize(15)
.fontColor('#475569')
}
.width('100%')
.lineHeight(24)
}
.width('100%')
.padding(16)
.backgroundColor('#EFF6FF')
.borderRadius(8)
Column({ space: 12 }) {
this.sectionTitle('ImageSpan 图文混排')
Text() {
ImageSpan($r('app.media.startIcon'))
.width(18)
.height(18)
.verticalAlign(ImageSpanAlignment.CENTER)
.objectFit(ImageFit.Contain)
Span(' 会员标识可以跟文字在同一行,不用额外写 Row 去拼。')
.fontSize(15)
.fontColor('#334155')
}
.width('100%')
.lineHeight(26)
Text() {
Span('支持 ')
.fontSize(15)
.fontColor('#475569')
ImageSpan($r('app.media.icon_huawei'))
.width(18)
.height(18)
.verticalAlign(ImageSpanAlignment.CENTER)
.objectFit(ImageFit.Contain)
Span(' 这种小图标跟文字自然对齐,适合放在说明、标签或状态文案里。')
.fontSize(15)
.fontColor('#475569')
}
.width('100%')
.lineHeight(26)
}
.width('100%')
.padding(16)
.backgroundColor('#F7FEE7')
.borderRadius(8)
Column({ space: 12 }) {
this.sectionTitle('行高和对齐')
Text('长文本不要只设置字号。行高太紧,读起来会挤;行高太松,页面会散。这个段落设置了 lineHeight,让多行文字更容易扫读。')
.width('100%')
.fontSize(15)
.fontColor('#334155')
.lineHeight(25)
Text('居中适合短标题,不适合长正文')
.width('100%')
.fontSize(16)
.fontWeight(700)
.fontColor('#0F766E')
.textAlign(TextAlign.Center)
}
.width('100%')
.padding(16)
.backgroundColor('#F0FDFA')
.borderRadius(8)
Column({ space: 12 }) {
this.sectionTitle('多行截断')
Text('这是一段故意写长的文字,用来展示 maxLines 和 textOverflow。真实业务里,卡片标题、列表摘要、商品描述都可能需要截断,否则一个长句就能把整个布局撑乱。')
.width('100%')
.fontSize(15)
.fontColor('#334155')
.lineHeight(24)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width('100%')
.padding(16)
.backgroundColor('#FFF7ED')
.borderRadius(8)
}
.width('100%')
.padding(20)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
}
- 点赞
- 收藏
- 关注作者
评论(0)