# 自定义字体的注册和使用(ArkTS) ## 场景介绍 自定义字体是指开发者根据应用需求创建或选择的字体,通常用于实现特定的文字风格或满足独特的设计要求。当应用需要使用特定的文本样式和字符集时,可以注册并使用自定义字体进行文本渲染。 ## 实现流程 **自定义字体的注册**是指将字体文件(如ttf、otf文件等)从应用资源注册到系统中,使得应用能够使用这些字体进行文本渲染。注册过程是将字体文件通过字体管理接口注册到系统字体库中,以便在应用中进行调用。 **自定义字体的使用**是指在应用中显式指定使用已注册的自定义字体进行文本渲染。开发者可以根据需要选择特定的文本样式(如常规、粗体、斜体等),并将其应用到UI元素、文本控件或其他文本展示区域,以满足设计要求并提供视觉效果的一致性。 ## 接口说明 自定义字体注册和使用的常用接口如下表所示,详细接口说明请见[@ohos.graphics.text (文本模块)](../reference/apis-arkgraphics2d/js-apis-graphics-text.md)。 | 接口 | 描述 | | -------- | -------- | | loadFontSync(name: string, path: string \| Resource): void | 同步接口,将路径对应的文件,以name作为使用的别名,注册自定义字体。
**说明:**
需保证使用自定义字体时,自定义字体已完成注册,非性能严格要求场景下,建议使用同步接口。 | | loadFont(name: string, path: string \| Resource): Promise<void> | 使用指定的别名和文件路径注册对应字体,使用Promise异步回调。此接口从API version 14开始支持。 | | unloadFontSync(name: string): void | 同步接口,注销指定别名的字体。此接口从API version 20开始支持。 | | unloadFont(name: string): Promise\ | 使用指定的别名注销对应字体,使用Promise异步回调。此接口从API version 20开始支持。 | ## 开发步骤 1. 导入依赖的相关模块。 ```ts import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' import { UIContext } from '@kit.ArkUI' import { text } from '@kit.ArkGraphics2D' ``` 2. 注册自定义字体。有以下两种方式: ```ts // 注册自定义字体 let fontCollection = text.FontCollection.getGlobalInstance() // 方式一:/system/fonts/myFontFile.ttf文件仅为示例路径,应用根据自身实际填写文件路径 fontCollection.loadFontSync('myFamilyName0', 'file:///system/fonts/myFontFile.ttf') // 方式二:确保已经将自定义字体myFontFile.ttf文件放在本应用工程的entry/src/main/resources/rawfile目录 fontCollection.loadFontSync('myFamilyName1',$rawfile('myFontFile.ttf')) ``` 3. 使用自定义字体。 ```ts // 填写注册自定义字体时传入的字体家族名 let myFontFamily: Array = ["myFamilyName0"] // 设置文本样式 let myTextStyle: text.TextStyle = { color: { alpha: 255, red: 255, green: 0, blue: 0 }, fontSize: 100, // 在文本样式中加入可使用的自定义字体 fontFamilies: myFontFamily }; ``` 4. 创建段落样式,并使用字体管理器实例构造段落生成器ParagraphBuilder实例。 ```ts // 创建一个段落样式对象,以设置排版风格 let myParagraphStyle: text.ParagraphStyle = {textStyle: myTextStyle} // 创建一个段落生成器 let paragraphBuilder: text.ParagraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); ``` 5. 生成段落。 ```ts // 在段落生成器中设置文本样式 paragraphBuilder.pushStyle(myTextStyle); // 在段落生成器中设置文本内容 paragraphBuilder.addText("Custom font test"); // 通过段落生成器生成段落 let paragraph = paragraphBuilder.build(); ``` 6. 如果需要释放自定义字体,可以使用unloadFontSync接口。 ```ts // 注销自定义字体 fontCollection.unloadFontSync(familyName) // 注销之后需要刷新使用该fontCollection的节点 newNode.invalidate() ``` ## 完整示例 这里以使用自定义注册字体方式一为例绘制“Custom font test”文本,并提供如下完整示例。 请保证自定义字体文件已放置到设备正确的路径下。 ```ts // Index.ets import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' import { UIContext } from '@kit.ArkUI' import { text } from '@kit.ArkGraphics2D' // 获取全局字体集实例 let fontCollection = text.FontCollection.getGlobalInstance() //获取Arkui全局FC const familyName = "myFamilyName" // 创建一个自定义的渲染节点类,用于绘制文本 class MyRenderNode extends RenderNode { async draw(context: DrawContext) { // 创建画布canvas对象 const canvas = context.canvas // 使用自定义字体 let myFontFamily: Array = [familyName] // 如果已经注册自定义字体,填入自定义字体的字体家族名 // 设置文本样式 let myTextStyle: text.TextStyle = { color: { alpha: 255, red: 255, green: 0, blue: 0 }, fontSize: 30, // 在文本样式中加入可使用的自定义字体 fontFamilies: myFontFamily }; // 创建一个段落样式对象,以设置排版风格 let myParagraphStyle: text.ParagraphStyle = { textStyle: myTextStyle, align: 3, wordBreak: text.WordBreak.NORMAL }; // 创建一个段落生成器 let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection) // 在段落生成器中设置文本样式 ParagraphGraphBuilder.pushStyle(myTextStyle); // 在段落生成器中设置文本内容 ParagraphGraphBuilder.addText("Custom font test"); // 通过段落生成器生成段落 let paragraph = ParagraphGraphBuilder.build(); // 设置段落宽度为1000px paragraph.layoutSync(1000); paragraph.paint(canvas, 0, 400); } } // 创建并初始化渲染节点实例 const newNode = new MyRenderNode(); // 设置渲染节点的位置和尺寸 newNode.frame = { x: 0, y: 0, width: 400, height: 600 }; class MyNodeController extends NodeController { private rootNode: FrameNode | null = null; makeNode(uiContext: UIContext): FrameNode { this.rootNode = new FrameNode(uiContext) if (this.rootNode == null) { return this.rootNode } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.frame = { x: 0, y: 0, width: 300, height: 50 } renderNode.pivot = { x: 0, y: 0 } } return this.rootNode } addNode(node: RenderNode): void { if (this.rootNode == null) { return } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.appendChild(node) } } clearNodes(): void { if (this.rootNode == null) { return } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.clearChildren() } } } @Entry @Component struct RenderTest { private myNodeController: MyNodeController = new MyNodeController() build() { Column() { Row() { // 如果使用getGlobalInstance的fontCollection注册字体,使用对应family name的组件会自动刷新 Text("Text Component") .fontFamily(familyName) NodeContainer(this.myNodeController) .height('100%') .onAppear(() => { this.myNodeController.clearNodes() this.myNodeController.addNode(newNode) }) } .height('90%') .backgroundColor(Color.White) Row() { Button("load font") .fontSize('16fp') .fontWeight(500) .margin({ bottom: 24, right: 12 }) .onClick(() => { // 注册自定义字体 fontCollection.loadFontSync(familyName, 'file:///system/fonts/NotoSansMalayalamUI-SemiBold.ttf') // 注册之后需要刷新使用该fontCollection的节点 newNode.invalidate() }) .width('30%') .height(40) .shadow(ShadowStyle.OUTER_DEFAULT_LG) Button("unload font") .fontSize('16fp') .fontWeight(500) .margin({ bottom: 24, right: 12 }) .onClick(() => { // 注销自定义字体 fontCollection.unloadFontSync(familyName) // 注销之后需要刷新使用该fontCollection的节点 newNode.invalidate() }) .width('30%') .height(40) .shadow(ShadowStyle.OUTER_DEFAULT_LG) } .width('100%') .justifyContent(FlexAlign.Center) // 设置当前Row容器内子元素在主轴上居中对齐 .shadow(ShadowStyle.OUTER_DEFAULT_SM) // 设置Row容器外阴影效果 .alignItems(VerticalAlign.Bottom) // 设置当前Row容器内子元素在交叉轴(垂直方向)上的对齐方式为底部对齐 .layoutWeight(1) // 设置当前Row在父容器Column中的布局权重为1 } } } ``` ## 效果展示 ![zh-cn_image_load](figures/zh-cn_image_load.png) ![zh-cn_image_unload](figures/zh-cn_image_unload.png)