想用自定义字体Typeface 让你轻松管理字体文件你有没有想过在 APP 里使用一种特别的字体比如用一种手写体来显示标题或者用一种等宽字体来显示代码在 HarmonyOS 的 drawing 模块里Typeface类就是专门用来管理字体的。Typeface 是什么下面是 Typeface 字体加载的各种方式系统字体目录应用 rawfile 目录是否需要加载自定义字体字体文件位置?makeFromFile 指定路径makeFromRawFile 引用资源需要指定字体属性?使用 WithArguments 版本直接使用基础版本传入 TypefaceArguments 配置字重等获得 Typeface 对象通过 font.setTypeface 设置到 Font用 Font 绘制文字简单说Typeface 就代表一种字体。我们平时说的宋体、“楷体”、“黑体”在代码里就是不同的 Typeface 对象。每个 Typeface 对象对应一种字体设计包含了该字体的所有字形信息。Typeface 和 Font 的关系是Font 是字型控制文字的大小、粗细、倾斜等属性Typeface 是字体决定文字用哪种设计风格。你可以把 Typeface 理解为字体文件Font 理解为字体设置。获取字体族名getFamilyName每个字体都有一个族名就是这套字体设计的名称。你可以用getFamilyName来获取import{drawing}fromkit.ArkGraphics2D;constfontnewdrawing.Font();lettypefacefont.getTypeface();letfamilyNametypeface.getFamilyName();这段代码先从 Font 对象获取关联的 Typeface然后获取它的族名。族名通常是一个有意义的字符串比如 “HarmonyOS Sans”、“Roboto” 等。从字体文件加载makeFromFile如果你想使用系统里的某个字体文件用makeFromFileimport{RenderNode}fromkit.ArkUI;import{drawing}fromkit.ArkGraphics2D;classTextRenderNodeextendsRenderNode{asyncdraw(context:DrawContext){constcanvascontext.canvas;letfontnewdrawing.Font();letstr/system/fonts/HarmonyOS_Sans_Italic.ttf;constmytypefacedrawing.Typeface.makeFromFile(str);font.setTypeface(mytypeface);consttextBlobdrawing.TextBlob.makeFromString(Hello World,font,drawing.TextEncoding.TEXT_ENCODING_UTF8);canvas.drawTextBlob(textBlob,60,100);}}这里我们加载了系统自带的斜体字体文件HarmonyOS_Sans_Italic.ttf然后用font.setTypeface把它设置到 Font 上。之后用这个 Font 绘制的文字就会使用斜体样式。makeFromFile的参数是字体文件的路径。你可以用系统字体路径如/system/fonts/也可以用应用沙箱路径。从 rawfile 加载makeFromRawFile如果你把字体文件打包在应用的 rawfile 目录下可以用makeFromRawFile来加载import{RenderNode}fromkit.ArkUI;import{drawing}fromkit.ArkGraphics2D;classTextRenderNodeextendsRenderNode{asyncdraw(context:DrawContext){constcanvascontext.canvas;letfontnewdrawing.Font();constmyTypeFacedrawing.Typeface.makeFromRawFile($rawfile(HarmonyOS_Sans_Bold.ttf));font.setTypeface(myTypeFace);consttextBlobdrawing.TextBlob.makeFromString(Hello World,font,drawing.TextEncoding.TEXT_ENCODING_UTF8);canvas.drawTextBlob(textBlob,60,100);}}$rawfile(HarmonyOS_Sans_Bold.ttf)引用的是resources/rawfile/HarmonyOS_Sans_Bold.ttf文件。你也可以放在子目录里比如$rawfile(ttf/HarmonyOS_Sans_Bold.ttf)。这种方式的好处是字体文件会随应用一起打包不依赖系统字体。带字体属性加载makeFromFileWithArguments / makeFromRawFileWithArguments从 API version 20 开始你可以在加载字体的时候就指定字体属性import{RenderNode}fromkit.ArkUI;import{drawing}fromkit.ArkGraphics2D;classTextRenderNodeextendsRenderNode{asyncdraw(context:DrawContext){constcanvascontext.canvas;letfontnewdrawing.Font();letstr/system/fonts/HarmonyOS_Sans_Italic.ttf;lettypeFaceArgumentnewdrawing.TypefaceArguments();constmyTypeFacedrawing.Typeface.makeFromFileWithArguments(str,typeFaceArgument);font.setTypeface(myTypeFace);consttextBlobdrawing.TextBlob.makeFromString(Hello World,font,drawing.TextEncoding.TEXT_ENCODING_UTF8);canvas.drawTextBlob(textBlob,60,100);}}import{RenderNode}fromkit.ArkUI;import{drawing}fromkit.ArkGraphics2D;classTextRenderNodeextendsRenderNode{asyncdraw(context:DrawContext){constcanvascontext.canvas;letfontnewdrawing.Font();lettypeFaceArgumentnewdrawing.TypefaceArguments();constmyTypeFacedrawing.Typeface.makeFromRawFileWithArguments($rawfile(HarmonyOS_Sans_Bold.ttf),typeFaceArgument);font.setTypeface(myTypeFace);consttextBlobdrawing.TextBlob.makeFromString(Hello World,font,drawing.TextEncoding.TEXT_ENCODING_UTF8);canvas.drawTextBlob(textBlob,60,100);}}TypefaceArguments可以让你指定字体的变体参数比如字重具体用法我们在下一篇文章里会详细讲。基于当前字体创建变体makeFromCurrent如果你已经有一个 Typeface 对象想基于它创建一个变体比如改变字重可以用makeFromCurrentimport{RenderNode}fromkit.ArkUI;import{drawing}fromkit.ArkGraphics2D;classTextRenderNodeextendsRenderNode{asyncdraw(context:DrawContext){constcanvascontext.canvas;lettypeArgumentsnewdrawing.TypefaceArguments();typeArguments.addVariation(wght,100);constmyTypeFacedrawing.Typeface.makeFromFile(/system/fonts/HarmonyOS_Sans_SC.ttf);consttypeFace1myTypeFace.makeFromCurrent(typeArguments);letfontnewdrawing.Font();font.setTypeface(typeFace1);consttextBlobdrawing.TextBlob.makeFromString(Hello World,font,drawing.TextEncoding.TEXT_ENCODING_UTF8);canvas.drawTextBlob(textBlob,60,100);}}这段代码先加载了HarmonyOS_Sans_SC.ttf然后基于它创建了一个字重为 100非常细的变体。TypefaceArguments的具体用法我们在下一篇文章里会详细讲。检查字体属性isBold / isItalic从 API version 23 开始你可以检查一个 Typeface 是否是粗体或斜体import{drawing}fromkit.ArkGraphics2D;constfontnewdrawing.Font();lettypefacefont.getTypeface();letisBoldtypeface.isBold();letisItalictypeface.isItalic();这两个方法在需要根据字体样式做不同处理时很有用。比如你可能想根据当前字体是否是粗体来决定是否需要额外加粗。实际应用场景下面是多语言字体选择的典型流程包含中文字符纯英文字符需要等宽字体需要绘制文字检测文字语言使用中文 Typeface使用英文 Typeface使用 monospace Typeface设置到 Font 对象设置字号和其他属性创建 TextBlob调用 canvas.drawTextBlob 绘制场景一使用自定义品牌字体很多 APP 都有自己的品牌字体。你可以把字体文件放在 rawfile 目录下然后用 Typeface 加载letbrandFontdrawing.Typeface.makeFromRawFile($rawfile(MyBrandFont.ttf));letfontnewdrawing.Font();font.setTypeface(brandFont);font.setSize(24);// 用这个 font 绘制品牌文字场景二代码高亮显示做代码编辑器或代码显示功能时通常需要等宽字体letcodeFontdrawing.Typeface.makeFromFile(/system/fonts/monospace.ttf);letfontnewdrawing.Font();font.setTypeface(codeFont);font.setSize(14);// 用这个 font 显示代码场景三多语言支持不同语言可能需要不同的字体。比如中文用一种字体英文用另一种letchineseFontdrawing.Typeface.makeFromFile(/system/fonts/HarmonyOS_Sans_SC.ttf);letenglishFontdrawing.Typeface.makeFromFile(/system/fonts/HarmonyOS_Sans.ttf);// 根据文本内容选择字体functiongetFontForText(text:string):drawing.Font{letfontnewdrawing.Font();if(/[\u4e00-\u9fa5]/.test(text)){font.setTypeface(chineseFont);}else{font.setTypeface(englishFont);}font.setSize(20);returnfont;}场景四字体变体切换同一个字体族可能有多种变体细体、常规、粗体等用 Typeface 可以方便地切换letregularTypefacedrawing.Typeface.makeFromFile(/system/fonts/HarmonyOS_Sans_Regular.ttf);letboldTypefacedrawing.Typeface.makeFromFile(/system/fonts/HarmonyOS_Sans_Bold.ttf);letitalicTypefacedrawing.Typeface.makeFromFile(/system/fonts/HarmonyOS_Sans_Italic.ttf);// 根据需要选择不同的变体注意事项API 版本Typeface 基础方法从 API version 11 开始支持makeFromFile从 12 开始makeFromRawFile从 18 开始带 Arguments 的方法从 20 开始isBold/isItalic从 23 开始。物理像素和其他 drawing 对象一样使用物理像素单位。线程安全单线程模型需要自己管理线程安全。字体文件路径确保字体文件路径正确文件存在且可读。如果文件不存在makeFromFile可能会返回空指针。性能考虑加载字体文件是一个相对耗时的操作建议把常用的 Typeface 对象缓存起来重复使用而不是每次需要时都重新加载。小结Typeface 是 drawing 模块里管理字体的核心类。它让你能够从系统字体或 rawfile 加载自定义字体获取字体的族名基于现有字体创建变体检查字体是否是粗体或斜体在实际开发中Typeface 通常和 Font 配合使用——Typeface 决定用什么字体Font 决定怎么显示。掌握了 Typeface你就能在 APP 里使用任何你喜欢的字体了。