HarmonyOS鸿蒙Next中注册自定义字体,Text渲染和Canvas绘制时缺失部分字体(没有绘制)
HarmonyOS鸿蒙Next中注册自定义字体,Text渲染和Canvas绘制时缺失部分字体(没有绘制)
功能描述
当前有个场景,自定义字体可能是本地的,也可能是云测下载下来的,需要使用Canvas去绘制或Text去渲染。
问题
当前我在注册字体成功后,进入页面,Canvas在绘制或Text渲染文章时,某些字或者所有文字可能缺失,视觉效果上看不到字。(重启应用后恢复正常, 简单的销毁页面重建则无法恢复)
注册字体在进入页面之前的,且注册成功后,才放行进入到对应界面,切进入页面后又加了120ms的延时渲染,但还是有概率出现此问题。
版本信息

更多关于HarmonyOS鸿蒙Next中注册自定义字体,Text渲染和Canvas绘制时缺失部分字体(没有绘制)的实战教程也可以访问 https://www.itying.com/category-93-b0.html
您好,未复现问题,可以提供复现问题的可运行最小化demo嘛,或者您可以参考以下 Canvas绘制自定义字体可以调用字体引擎的fontCollection.loadFontSync接口来注册自定义字体,示例可以参照官网font属性
import { text } from '@kit.ArkGraphics2D';
@Entry
@Component
struct FontDemo {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('rgb(213,213,213)')
.onReady(() => {
// 加载rawfile目录下的自定义字体文件myFont.ttf
let fontCollection = text.FontCollection.getGlobalInstance();
fontCollection.loadFontSync('HarmonyOS_Sans_Thin_Italic', $rawfile("myFont.ttf"))
// 加粗,字体大小为30vp,字体系列为HarmonyOS_Sans_Thin_Italic
this.context.font = "bold 30vp HarmonyOS_Sans_Thin_Italic"
this.context.fillText("Hello customFont", 20, 140)
})
}
.width('100%')
.height('100%')
}
}
更多关于HarmonyOS鸿蒙Next中注册自定义字体,Text渲染和Canvas绘制时缺失部分字体(没有绘制)的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
我调用的就是这个,我们这边自定义字体比较多,它是有概率出现的,我们这边基本上20个复现一个:
它这个不止Canvas有问题,Text使用也有一样的问题
您好,本地尝试未复现,麻烦您提供以下信息以便进行排查
可复现问题的完整Demo以及IDE和设备版本号
补充一个定位思路:既然 Text 也会缺字,先别把问题只归到 Canvas。ctx.font 只有在字体已经被字体引擎注册且 family 名一致时才会命中自定义字体;API20+ 才明确支持注册字体。建议入口处只加载一次全局 FontCollection,绘制前用同一个 family 预热,再检测是否是字体包本身缺 glyph。
import { text } from '@kit.ArkGraphics2D'
const fc = text.FontCollection.getGlobalInstance()
fc.loadFontSync('BizFont','rawfile/font/biz.ttf')
Canvas(this.ctx).onReady(() => {
this.ctx.font = '28px BizFont'
this.ctx.fillText('待验证文字', 20, 40)
})
排查:1. BizFont 与 ctx.font 完全一致;2. 真机验证,预览器不支持自定义字体;3. 开启 setTextUndefinedGlyphDisplay(USE_TOFU),若缺字变方块就是字体子集缺字形。参考文档:CanvasRenderingContext2D.font、FontCollection.loadFontSync、@ohos.font 注册自定义字体。
这个问题从现象来看,不像是字体注册失败,而更像是字体注册完成后,Canvas 底层字体缓存(Font Manager)还没有完全就绪,导致部分 Glyph(字形)偶发丢失。
你描述的几个关键信息:
✓ registerFont 成功
✓ 页面进入前已完成注册
✓ 进入页面后又延迟120ms
✗ Canvas绘制时偶发缺字
✗ 同一个字体有时正常有时缺失
这种情况我更倾向于下面几个方向。
第一种可能(概率最高)
字体注册成功 ≠ 字体加载完成
很多字体系统实际上是:
registerFont
↓
加入字体管理器
↓
异步解析TTF/OTF
↓
建立Glyph缓存
↓
首次Raster
而Canvas的:
ctx.fillText(...)
可能在:
Glyph Cache建立前
就开始绘制了。
于是出现:
汉字A 正常
汉字B 缺失
汉字C 正常
因为:
A 已缓存
B 未缓存
这种现象在Canvas体系里非常常见。
第二种可能
下载字体后立即注册
你提到:
字体可能来自云端下载
重点检查:
download()
↓
writeFile()
↓
registerFont()
之间有没有:
fsync
flush
close
真正完成。
很多时候:
文件已存在
≠
文件已完全写入
尤其大字体:
思源黑体
HarmonyOS Sans
阿里巴巴普惠体
10~30MB很常见。
可能出现:
注册时读取到了不完整文件
导致部分字形表异常。
第三种可能
字体本身缺Glyph
这个要重点排查。
很多设计字体:
只支持:
ASCII
数字
常用汉字
不支持:
扩展汉字
生僻字
特殊符号
Emoji
例如:
𠮷
㵘
㎏
①
™
®
Canvas不会自动字体回退时,就会出现:
整个字符消失
而不是显示方块。
建议打印:
text.codePointAt(i)
看看缺失的是不是固定字符。
第四种可能
Canvas字体缓存Bug
目前你用的是:
HarmonyOS 6.1.1
API24
从版本来看:
OpenHarmony SDK
6.1.1.125
已经属于较新的SDK。
但Canvas文字渲染底层是:
ArkUI
↓
Skia
↓
FontManager
如果:
首次使用动态注册字体
可能存在:
FontCache未刷新
情况。
表现就是:
第一次缺字
第二次正常
建议验证
验证1
注册后先用Text组件渲染一次
Text("测试字体加载")
.fontFamily("MyFont")
.opacity(0.01)
不要直接Canvas。
流程:
registerFont
↓
Text先渲染
↓
等待一帧
↓
Canvas绘制
很多字体缓存问题会直接消失。
验证2
首次绘制两次
ctx.fillText(text, x, y)
setTimeout(() => {
ctx.clearRect(...)
ctx.fillText(text, x, y)
}, 50)
如果:
第一次缺
第二次正常
基本可以确认:
Font Cache问题
验证3
统计缺失字符
例如:
const text = "中华人民共和国"
for (let i = 0; i < text.length; i++) {
console.info(text[i])
}
记录:
哪一个字缺失
观察:
总是同一个字缺
还是随机缺
如果总是同一个字
大概率:
字体文件问题
如果随机缺
大概率:
Canvas字体缓存问题
第五种可能
Canvas比Text更容易触发问题
很多开发者容易忽略:
Text组件
和
Canvas.fillText()
底层并不是完全同一套流程。
经常出现:
Text正常
Canvas缺字
或者:
Text支持字体回退
Canvas不支持
这种情况。
建议先验证:
Text()
.fontFamily(你的字体)
是否100%正常。
如果:
Text正常
Canvas异常
基本可以认定是Canvas渲染链路问题,而不是字体文件问题。
结合你的描述:
注册成功
延迟120ms
偶发缺字
本地字体和下载字体都能复现
我认为最可能的原因排序是:
① Canvas字体缓存未完成初始化(70%)
② Canvas动态字体渲染Bug(20%)
③ 字体文件Glyph缺失(8%)
④ 下载文件未完全落盘(2%)
如果这是准备向华为提单的问题,建议附上:
- 最小复现Demo
- 字体文件(ttf/otf)
- 缺失字符具体内容
- Text组件是否正常
- 第二次fillText是否恢复
这样研发基本能直接定位到是 ArkUI Canvas 字体缓存链路还是 FontManager 的问题。同样的逻辑,同样的代码,我抽成小demo后反而复现不出来
在HarmonyOS Next中注册自定义字体后,Text渲染和Canvas绘制缺失部分字符,通常因字体文件本身不包含这些字符的glyph,或注册时fontFamily名称与使用时不匹配。确保自定义字体文件为TTF/OTF格式且字符集完整,调用registerFont时fontFamily参数与Text或Canvas的font属性设置一致。若仍缺失,检查字体文件是否损坏。
字体注册虽然是同步调用,但系统字体的缓存刷新可能存在延迟,导致页面创建时字体尚未完全就绪,而重启应用会重新加载所有资源,因此表现正常。
可尝试以下方式解决:
- 注册提前:将字体注册放在
Ability的onCreate或onWindowStageCreate中,确保在页面渲染前已完成。 - 条件渲染:在注册成功后(可借助
fonts.isFontLoaded二次确认),再动态创建或显示使用自定义字体的 Text/Canvas 组件,避免组件在字体未就绪时已构建。 - Canvas 重绘:Canvas 绘制操作前显式调用
canvas.font = '...'重新指定字体,并在字体 ready 后通过状态变化触发重绘,而非仅依赖延时。 - 版本问题:若以上均无效,可能是系统早期版本的缺陷,请升级到最新的 HarmonyOS Next SDK 并重试。
核心在于保证字体完全加载后再开始绑定和绘制,避免组件实例化与字体缓存刷新的竞态。


