• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 自定义字体的注册和使用(ArkTS)
2<!--Kit: ArkGraphics 2D-->
3<!--Subsystem: Graphics-->
4<!--Owner: @oh_wangxk; @gmiao522; @Lem0nC-->
5<!--Designer: @liumingxiang-->
6<!--Tester: @yhl0101-->
7<!--Adviser: @ge-yafang-->
8## 场景介绍
9
10自定义字体是指开发者根据应用需求创建或选择的字体,通常用于实现特定的文字风格或满足独特的设计要求。当应用需要使用特定的文本样式和字符集时,可以注册并使用自定义字体进行文本渲染。
11
12## 实现流程
13
14**自定义字体的注册**是指将字体文件(如ttf、otf文件等)从应用资源注册到系统中,使得应用能够使用这些字体进行文本渲染。注册过程是将字体文件通过字体管理接口注册到系统字体库中,以便在应用中进行调用。
15
16**自定义字体的使用**是指在应用中显式指定使用已注册的自定义字体进行文本渲染。开发者可以根据需要选择特定的文本样式(如常规、粗体、斜体等),并将其应用到UI元素、文本控件或其他文本展示区域,以满足设计要求并提供视觉效果的一致性。
17
18
19## 接口说明
20
21自定义字体注册和使用的常用接口如下表所示,详细接口说明请见[@ohos.graphics.text (文本模块)](../reference/apis-arkgraphics2d/js-apis-graphics-text.md)。
22
23| 接口 | 描述 |
24| -------- | -------- |
25| loadFontSync(name: string, path: string \| Resource): void | 同步接口,将路径对应的文件,以name作为使用的别名,注册自定义字体。<br/>**说明:**<br/>需保证使用自定义字体时,自定义字体已完成注册,非性能严格要求场景下,建议使用同步接口。 |
26| loadFont(name: string, path: string \| Resource): Promise&lt;void&gt; | 使用指定的别名和文件路径注册对应字体,使用Promise异步回调。此接口从API version 14开始支持。 |
27| unloadFontSync(name: string): void | 同步接口,注销指定别名的字体。此接口从API version 20开始支持。 |
28| unloadFont(name: string): Promise\<void\> | 使用指定的别名注销对应字体,使用Promise异步回调。此接口从API version 20开始支持。 |
29
30## 开发步骤
31
321. 导入依赖的相关模块。
33
34   ```ts
35   import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'
36   import { UIContext } from '@kit.ArkUI'
37   import { text } from '@kit.ArkGraphics2D'
38   ```
39
402. 注册自定义字体。有以下两种方式:
41
42   ```ts
43   // 注册自定义字体
44   let fontCollection = text.FontCollection.getGlobalInstance()
45   // 方式一:/system/fonts/myFontFile.ttf文件仅为示例路径,应用根据自身实际填写文件路径
46   fontCollection.loadFontSync('myFamilyName0', 'file:///system/fonts/myFontFile.ttf')
47
48   // 方式二:确保已经将自定义字体myFontFile.ttf文件放在本应用工程的entry/src/main/resources/rawfile目录
49   fontCollection.loadFontSync('myFamilyName1',$rawfile('myFontFile.ttf'))
50   ```
51
523. 使用自定义字体。
53
54   ```ts
55   // 填写注册自定义字体时传入的字体家族名
56   let myFontFamily: Array<string> = ["myFamilyName0"]
57   // 设置文本样式
58   let myTextStyle: text.TextStyle = {
59     color: { alpha: 255, red: 255, green: 0, blue: 0 },
60     fontSize: 100,
61     // 在文本样式中加入可使用的自定义字体
62     fontFamilies: myFontFamily
63   };
64   ```
65
664. 创建段落样式,并使用字体管理器实例构造段落生成器ParagraphBuilder实例。
67
68   ```ts
69   // 创建一个段落样式对象,以设置排版风格
70   let myParagraphStyle: text.ParagraphStyle = {textStyle: myTextStyle}
71   // 创建一个段落生成器
72   let paragraphBuilder: text.ParagraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
73   ```
74
755. 生成段落。
76
77   ```ts
78   // 在段落生成器中设置文本样式
79   paragraphBuilder.pushStyle(myTextStyle);
80   // 在段落生成器中设置文本内容
81   paragraphBuilder.addText("Custom font test");
82   // 通过段落生成器生成段落
83   let paragraph = paragraphBuilder.build();
84   ```
85
866. 如果需要释放自定义字体,可以使用unloadFontSync接口。
87
88   ```ts
89   // 注销自定义字体
90   fontCollection.unloadFontSync(familyName)
91   // 注销之后需要刷新使用该fontCollection的节点
92   newNode.invalidate()
93   ```
94
95## 完整示例
96
97这里以使用自定义注册字体方式一为例绘制“Custom font test”文本,并提供如下完整示例。
98
99请保证自定义字体文件已放置到设备正确的路径下。
100
101```ts
102// Index.ets
103import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'
104import { UIContext } from '@kit.ArkUI'
105import { text } from '@kit.ArkGraphics2D'
106
107// 获取全局字体集实例
108let fontCollection = text.FontCollection.getGlobalInstance() //获取Arkui全局FC
109const familyName = "myFamilyName"
110
111// 创建一个自定义的渲染节点类,用于绘制文本
112class MyRenderNode extends RenderNode {
113  async draw(context: DrawContext) {
114    // 创建画布canvas对象
115    const canvas = context.canvas
116    // 使用自定义字体
117    let myFontFamily: Array<string> = [familyName] // 如果已经注册自定义字体,填入自定义字体的字体家族名
118    // 设置文本样式
119    let myTextStyle: text.TextStyle = {
120      color: {
121        alpha: 255,
122        red: 255,
123        green: 0,
124        blue: 0
125      },
126      fontSize: 30,
127      // 在文本样式中加入可使用的自定义字体
128      fontFamilies: myFontFamily
129    };
130    // 创建一个段落样式对象,以设置排版风格
131    let myParagraphStyle: text.ParagraphStyle = {
132      textStyle: myTextStyle,
133      align: 3,
134      wordBreak: text.WordBreak.NORMAL
135    };
136    // 创建一个段落生成器
137    let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection)
138    // 在段落生成器中设置文本样式
139    ParagraphGraphBuilder.pushStyle(myTextStyle);
140    // 在段落生成器中设置文本内容
141    ParagraphGraphBuilder.addText("Custom font test");
142    // 通过段落生成器生成段落
143    let paragraph = ParagraphGraphBuilder.build();
144    // 设置段落宽度为1000px
145    paragraph.layoutSync(1000);
146    paragraph.paint(canvas, 0, 400);
147  }
148}
149
150// 创建并初始化渲染节点实例
151const newNode = new MyRenderNode();
152// 设置渲染节点的位置和尺寸
153newNode.frame = {
154  x: 0,
155  y: 0,
156  width: 400,
157  height: 600
158};
159
160
161class MyNodeController extends NodeController {
162  private rootNode: FrameNode | null = null;
163
164  makeNode(uiContext: UIContext): FrameNode {
165    this.rootNode = new FrameNode(uiContext)
166    if (this.rootNode == null) {
167      return this.rootNode
168    }
169    const renderNode = this.rootNode.getRenderNode()
170    if (renderNode != null) {
171      renderNode.frame = {
172        x: 0,
173        y: 0,
174        width: 300,
175        height: 50
176      }
177      renderNode.pivot = { x: 0, y: 0 }
178    }
179    return this.rootNode
180  }
181
182  addNode(node: RenderNode): void {
183    if (this.rootNode == null) {
184      return
185    }
186    const renderNode = this.rootNode.getRenderNode()
187    if (renderNode != null) {
188      renderNode.appendChild(node)
189    }
190  }
191
192  clearNodes(): void {
193    if (this.rootNode == null) {
194      return
195    }
196    const renderNode = this.rootNode.getRenderNode()
197    if (renderNode != null) {
198      renderNode.clearChildren()
199    }
200  }
201}
202
203@Entry
204@Component
205struct RenderTest {
206  private myNodeController: MyNodeController = new MyNodeController()
207
208  build() {
209    Column() {
210      Row() {
211        // 如果使用getGlobalInstance的fontCollection注册字体,使用对应family name的组件会自动刷新
212        Text("Text Component")
213          .fontFamily(familyName)
214        NodeContainer(this.myNodeController)
215          .height('100%')
216          .onAppear(() => {
217            this.myNodeController.clearNodes()
218            this.myNodeController.addNode(newNode)
219          })
220      }
221      .height('90%')
222      .backgroundColor(Color.White)
223
224      Row() {
225        Button("load font")
226          .fontSize('16fp')
227          .fontWeight(500)
228          .margin({ bottom: 24, right: 12 })
229          .onClick(() => {
230            // 注册自定义字体
231            fontCollection.loadFontSync(familyName, 'file:///system/fonts/NotoSansMalayalamUI-SemiBold.ttf')
232            // 注册之后需要刷新使用该fontCollection的节点
233            newNode.invalidate()
234          })
235          .width('30%')
236          .height(40)
237          .shadow(ShadowStyle.OUTER_DEFAULT_LG)
238        Button("unload font")
239          .fontSize('16fp')
240          .fontWeight(500)
241          .margin({ bottom: 24, right: 12 })
242          .onClick(() => {
243            // 注销自定义字体
244            fontCollection.unloadFontSync(familyName)
245            // 注销之后需要刷新使用该fontCollection的节点
246            newNode.invalidate()
247          })
248          .width('30%')
249          .height(40)
250          .shadow(ShadowStyle.OUTER_DEFAULT_LG)
251      }
252      .width('100%')
253      .justifyContent(FlexAlign.Center) // 设置当前Row容器内子元素在主轴上居中对齐
254      .shadow(ShadowStyle.OUTER_DEFAULT_SM) // 设置Row容器外阴影效果
255      .alignItems(VerticalAlign.Bottom) // 设置当前Row容器内子元素在交叉轴(垂直方向)上的对齐方式为底部对齐
256      .layoutWeight(1) // 设置当前Row在父容器Column中的布局权重为1
257    }
258  }
259}
260```
261
262## 效果展示
263
264![zh-cn_image_load](figures/zh-cn_image_load.png)
265![zh-cn_image_unload](figures/zh-cn_image_unload.png)
266