鸿蒙开发-想做高级文本排版?text文本模块的排版和字体管理
文章摘要: HarmonyOS的text模块提供了强大的文本排版功能,支持自定义字体加载和精细排版控制。核心流程包括:获取字体集(FontCollection)、加载自定义字体、定义文本样式(TextStyle)和段落样式(ParagraphStyle)、通过段落生成器(ParagraphBuilder)构建段落对象,最终执行排版并获取结果。该模块支持同步/异步字体加载、多种排版参数设置,并能查询
高级文本排版?text 模块帮你搞定一切
你有没有遇到过这样的需求:在一个自定义绘制的界面上,需要精确控制文字的排版?比如做一个电子书阅读器,需要支持各种字体、字号、行间距;或者做一个图片编辑器,需要在图片上叠加文字,还要控制文字的位置和样式。
HarmonyOS 的 @ohos.graphics.text 模块就是干这个的。它提供了一套完整的文本排版和字体管理 API,能让你在自定义绘制场景中实现高质量的文本渲染。
导入模块
import { text } from '@kit.ArkGraphics2D'
核心概念:从字体到段落
下面是 text 模块排版的整体流程:
在开始写代码之前,先理解一下这个模块的核心概念:
- FontCollection(字体集):管理所有可用的字体,包括系统字体和自定义字体。
- TextStyle(文本样式):定义文字的外观,比如字体、字号、颜色、字重等。
- ParagraphStyle(段落样式):定义段落的排版规则,比如对齐方式、断行策略等。
- ParagraphBuilder(段落生成器):用来构建段落对象的工具,你可以往里面添加文字和样式。
- Paragraph(段落):最终的排版结果,可以测量尺寸、绘制到画布上。
打个比方,如果把排版比作盖房子:
FontCollection是你的建材库(有哪些砖、哪些瓦)TextStyle是装修方案(用什么材料、什么颜色)ParagraphStyle是建筑规范(房间怎么布局)ParagraphBuilder是施工队(按照方案和规范来盖)Paragraph是盖好的房子(可以测量面积、可以展示)
第一步:获取字体集
字体集是排版的基础,你得先告诉系统"我能用哪些字体"。
获取全局字体集:
import { text } from '@kit.ArkGraphics2D'
function textFunc() {
let fontCollection = text.FontCollection.getGlobalInstance();
}
@Entry
@Component
struct Index {
fun: Function = textFunc;
build() {
Column() {
Button().onClick(() => {
this.fun();
})
}
}
}
FontCollection.getGlobalInstance() 返回应用全局的字体集实例。这个实例在整个应用生命周期内都有效,包含了系统预装的所有字体。
获取本地字体集(推荐卡片场景):
import { text } from '@kit.ArkGraphics2D'
let fontCollection = text.FontCollection.getLocalInstance();
如果你在做 ArkTS 卡片,建议用 getLocalInstance(),它会创建一个独立的字体集实例,不会影响主应用。
第二步:加载自定义字体
系统自带的字体可能满足不了你的需求。比如你想用一个特殊的艺术字体来做标题,就需要加载自定义字体。
同步加载:
import { text } from '@kit.ArkGraphics2D'
let fontCollection: text.FontCollection = new text.FontCollection();
@Entry
@Component
struct RenderTest {
LoadFontSyncTest() {
fontCollection.loadFontSync('Clock_01', 'file:///system/fonts/HarmonyClock_01.ttf')
let fontFamilies: Array<string> = ["Clock_01"]
let myTextStyle: text.TextStyle = {
fontFamilies: fontFamilies
};
let myParagraphStyle: text.ParagraphStyle = {
textStyle: myTextStyle,
}
let paragraphBuilder: text.ParagraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
let textData = "测试 loadFontSync 加载字体HarmonyClock_01.ttf";
paragraphBuilder.addText(textData);
let paragraph: text.Paragraph = paragraphBuilder.build();
paragraph.layoutSync(600);
}
aboutToAppear() {
this.LoadFontSyncTest();
}
build() {
}
}
loadFontSync 的第一个参数是字体的别名(随便取),第二个参数是字体文件的路径。加载后,在 TextStyle 的 fontFamilies 里用这个别名就能使用这个字体了。
异步加载:
import { text } from '@kit.ArkGraphics2D'
let fontCollection: text.FontCollection = new text.FontCollection();
@Entry
@Component
struct RenderTest {
async loadFontPromise() {
fontCollection.loadFont('testName', 'file:///system/fonts/a.ttf').then((data) => {
console.info(`Succeeded in doing loadFont ${JSON.stringify(data)} `);
}).catch((error: Error) => {
console.error(`Failed to do loadFont, error: ${JSON.stringify(error)} message: ${error.message}`);
});
}
aboutToAppear() {
this.loadFontPromise();
}
build() {
}
}
异步加载不会阻塞 UI 线程,适合加载大字体文件的场景。
第三步:构建段落
有了字体集,就可以开始构建段落了。
let fontCollection: text.FontCollection = text.FontCollection.getGlobalInstance();
// 定义文本样式
let myTextStyle: text.TextStyle = {
fontFamilies: ["HarmonyOS Sans"],
fontSize: 24,
fontWeight: text.FontWeight.W400,
color: { alpha: 255, red: 0, green: 0, blue: 0 }
};
// 定义段落样式
let myParagraphStyle: text.ParagraphStyle = {
textStyle: myTextStyle,
align: text.TextAlign.LEFT,
maxLines: 5
};
// 创建段落构建器
let paragraphBuilder: text.ParagraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
// 添加文字
paragraphBuilder.addText("这是一段测试文字,用来演示 text 模块的排版功能。");
// 构建段落
let paragraph: text.Paragraph = paragraphBuilder.build();
// 设置排版宽度并执行排版
paragraph.layoutSync(600);
这段代码做了以下几件事:
- 定义了一个
TextStyle,设置了字体、字号、字重和颜色。 - 定义了一个
ParagraphStyle,设置了文本样式、对齐方式和最大行数。 - 创建了一个
ParagraphBuilder,传入段落样式和字体集。 - 用
addText添加文字内容。 - 调用
build()构建段落对象。 - 调用
layoutSync(600)设置排版宽度为 600 像素,并执行排版。
第四步:查询排版结果
段落排版完成后,你可以查询各种排版信息:
paragraph.getHeight():获取段落总高度paragraph.getLongestLine():获取最长一行的宽度paragraph.getLineCount():获取行数paragraph.getTextLines():获取所有行对象(TextLine)
每一行(TextLine)又可以进一步获取:
textLine.getGlyphRuns():获取这一行的所有排版单元(Run)
每个 Run 包含了连续的、使用相同样式的文字片段。通过 Run 你可以获取每个字符的位置信息,这在做文字选中、文字点击等交互时非常有用。
字体管理:查询系统字体
系统字体和自定义字体的加载方式有所不同,下面是字体加载的决策流程:
除了加载自定义字体,你还可以查询系统已有的字体。
按类型获取字体名称列表:
import { text } from '@kit.ArkGraphics2D'
import { BusinessError } from '@kit.BasicServicesKit'
@Entry
@Component
struct Index {
build() {
Row() {
Column() {
Button("get font list")
.fontSize(30)
.fontWeight(FontWeight.Bold)
.width(300)
.height(80)
.onClick(() => {
let fontType:text.SystemFontType = text.SystemFontType.GENERIC
let promise = text.getSystemFontFullNamesByType(fontType)
promise.then((data) => {
console.info(`then font list size: ${data.length}`)
data.forEach((fontItem) => {
console.info(fontItem)
})
}).catch((error: BusinessError) => {
console.error(`Failed to get font fullNames by type, error: ${JSON.stringify(error)}`);
});
})
}
.width('100%')
}
.height('100%')
}
}
根据字体名称获取字体描述符:
import { text } from '@kit.ArkGraphics2D'
import { BusinessError } from '@kit.BasicServicesKit'
@Entry
@Component
struct Index {
build() {
Row() {
Column() {
Button("get fontDescriptor")
.fontSize(30)
.fontWeight(FontWeight.Bold)
.width(300)
.height(80)
.onClick(() => {
let fontType:text.SystemFontType = text.SystemFontType.GENERIC
let promise = text.getFontDescriptorByFullName("HarmonyOS Sans", fontType)
promise.then((fontDescriptor) => {
console.info(`desc: ${JSON.stringify(fontDescriptor)}`)
}).catch((error: BusinessError) => {
console.error(`Failed to get fontDescriptor by fullName, error: ${JSON.stringify(error)}`);
});
})
}
.width('100%')
}
.height('100%')
}
}
字体描述符(FontDescriptor)包含了字体的详细信息:路径、名称、字重、宽度、是否斜体、是否等宽等。你可以用它来判断某个字体是否满足你的需求。
匹配字体描述符:
import { text } from '@kit.ArkGraphics2D'
import { BusinessError } from '@kit.BasicServicesKit'
@Entry
@Component
struct Index {
build() {
Row() {
Column() {
Button("font descriptor")
.fontSize(30)
.fontWeight(FontWeight.Bold)
.width(300)
.height(80)
.onClick(() => {
console.info(`Get font descriptor start`)
let promise = text.matchFontDescriptors({
weight: text.FontWeight.W400,
})
promise.then((data) => {
console.info(`Font descriptor array size: ${data.length}`);
console.info(`Font descriptor result: ${JSON.stringify(data)}`)
}).catch((error: BusinessError) => {
console.error(`Failed to match the font descriptor, error: ${JSON.stringify(error)}`);
});
})
}
.width('100%')
}
.height('100%')
}
}
matchFontDescriptors 可以根据你指定的条件(比如字重、是否等宽等)来搜索系统中符合条件的字体。这在做一个"字体选择器"功能时特别有用。
全局配置:高对比度文字和未定义字形
设置文字高对比度模式:
text.setTextHighContrast(text.TextHighContrast.TEXT_APP_DISABLE_HIGH_CONTRAST)
这个设置会影响整个进程的文字渲染。如果你的 APP 面向视力不好的用户,可以开启高对比度模式让文字更清晰。
设置未定义字形的显示方式:
text.setTextUndefinedGlyphDisplay(text.TextUndefinedGlyphDisplay.USE_TOFU)
当字体中没有某个字符的字形时,默认行为是用字体内部的 .notdef 字形(可能是空框或空格)。如果你设置成 USE_TOFU,就会强制用"豆腐块"(方框)来显示,方便你在开发阶段发现缺失的字符。
小结
text 模块是一个功能非常完整的文本排版引擎。它的核心流程是:
- 获取或创建字体集(FontCollection)
- 加载需要的字体(loadFontSync / loadFont)
- 定义文本样式和段落样式
- 用 ParagraphBuilder 构建段落
- 调用 layoutSync 排版
- 查询排版结果或绘制到画布
如果你的 APP 需要在自定义绘制场景中处理文本——不管是做电子书阅读器、图片编辑器、还是自定义 UI 组件——这个模块都能满足你的需求。
更多推荐

所有评论(0)