HarmonyOS 自定义字体设置实战:从字体注册到系统跟随完整方案
文章摘要 本文介绍了ArkUI框架中的字体控制功能,重点讲解了自定义字体应用与系统字体恢复的实现方法。主要内容包括:1) 通过registerFont()注册TTF/OTF字体文件;2) 使用preferences持久化存储字体选择;3) 实现字体动态切换的技术方案。具体开发步骤涵盖首选项工具类创建、字体注册方法定义、页面加载时字体初始化以及菜单交互逻辑处理。文中还特别说明了如何通过设置fontF
一、字体设置为啥重要
字体是用户界面核心视觉元素之一,直接影响应用美观性、可读性和用户体验。
ArkUI 提供的字体控制能力:
- 自定义设置字体大小和字重
- 通过
registerFont()注册 TTF 和 OTF 自定义字体文件 - 下载字体到沙箱内注册,实现动态切换
- 省略号、自动缩放、换行控制等文本溢出处理
本文讲四个场景:
- 使用自定义字体显示文本
- 从自定义字体恢复为系统字体
- 字体大小跟随系统设置
- 字体大小不跟随系统设置
二、使用自定义字体显示文本
场景咋回事
字体设置里,点击选择字体列表中某个字体,页面字体样式变化。退出应用重新进入,默认显示退出前选择的字体样式。

实现原理
registerFont() 在字体管理器注册自定义字体,支持 TTF 和 OTF 格式。
preferences(用户首选项)处理 Key-Value 数据,支持持久化轻量级数据,以及修改和查询。
开发步骤
第一步:创建首选项工具类
定义三个方法:
getTextFontPreference():获取首选项实例saveModifyFont():保存字体信息到首选项getFont():从首选项获取字体数据
export class PreferenceUtils {
preference?: preferences.Preferences;
// Get Preferences instance
getTextFontPreference(context: Context) {
try {
this.preference = preferences.getPreferencesSync(context, { name: 'TextFontPreference' });
hilog.info(0x0000, TAG, 'create preference success');
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, TAG, `create preference failed. code: ${error.code}, message:${err.message}`);
}
}
// Save Font
saveModifyFont(textFont: string) {
try {
this.preference?.putSync(TEXT_FONT, textFont);
this.preference?.flush((err: BusinessError) => {
if (err) {
hilog.error(0x0000, TAG, `Failed to flush. code:${err.code}, message:${err.message}`);
return;
}
hilog.info(0x0000, TAG, 'Succeeded in flushing.');
})
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, TAG,
`putSync or flush font preference data failed. code: ${error.code}, message:${err.message}`);
}
}
// Get Font
getFont(): string {
let textFont: string = '';
try {
textFont = this.preference?.getSync(TEXT_FONT, '') as string;
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, TAG, `getSync font preference data failed. code: ${error.code}, message:${err.message}`);
}
return textFont;
}
}
export default new PreferenceUtils();
第二步:EntryAbility 里获取首选项实例
在 onCreate() 生命周期调用:
export default class EntryAbility extends UIAbility {
onCreate(_want: Want, _launchParam: AbilityConstant.LaunchParam): void {
// Get preference instance
PreferenceUtils.getTextFontPreference(this.context);
}
}
第三步:定义注册字体方法
通过 UIContext 的 getFont() 获取 Font 对象,调用 registerFont() 注册字体:
// Register font
export function registerMyFont(uiContext: UIContext) {
try {
// Register HarmonyOS Italic font
uiContext.getFont().registerFont({
familyName: $r('app.string.HarmonyOS_Italic'),
familySrc: $rawfile('HarmonyOS_SansItalic.ttf')
});
// Register HarmonyOS Condensed font
uiContext.getFont().registerFont({
familyName: $r('app.string.HarmonyOS_Condensed'),
familySrc: $rawfile('HarmonyOS_Condensed.ttf')
});
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, TAG, `registerFont failed. code: ${error.code}, message:${err.message}`);
}
}
registerFont 参数:
familyName: 字体名称(用$r引用字符串资源)familySrc: 字体文件路径(用$rawfile引用 rawfile 目录下的字体文件)
第四步:页面加载时注册字体并读取首选项
用 @StorageLink 装饰变量 fontOffset,标识当前选择的字体。页面 aboutToAppear() 里注册字体并读取首选项:
@StorageLink('fontOffset') fontOffset: string = '';
aboutToAppear() {
// Get font data from preferences
this.fontOffset = PreferenceUtils.getFont();
// Register font
registerMyFont(this.getUIContext());
}
第五步:点击 MenuItem 保存字体选择
MenuItem 的 onChange() 事件里修改 fontOffset 并保存到首选项:
MenuItem({
content: item === '' ? $r('app.string.system_default') : item,
endIcon: this.fontOffset === item ? $r('app.media.checkmark') : ''
})
.onChange(() => {
this.fontOffset = item;
PreferenceUtils.saveModifyFont(item);
})
item 为空字符串表示系统默认字体,不为空是自定义字体名称。
第六步:用 fontFamily 属性应用字体
// Example Text Content
Column() {
Text($r('app.string.preview_text'))
.fontFamily(this.fontOffset)
}
.width('100%')
.padding(12)
.margin({ top: 35 })
.backgroundColor('#FFF')
.borderRadius(16)
fontFamily 传入 fontOffset 变量,显示对应字体样式。
三、从自定义字体恢复为系统字体
场景咋回事
字体设置里点击系统默认字体,页面字体变为系统默认。退出重新进入,仍显示系统默认字体。

实现原理
系统默认字体是无衬线字体 HarmonyOS Sans。当 fontFamily 显式设为空字符串时,效果和不设置 fontFamily 一致,回退到默认字体。字体样式、字重等其他属性正常应用。
开发步骤
跟使用自定义字体流程一样,关键点:
MenuItem 列表里第一个选项是空字符串(表示系统默认):
Menu() {
ForEach(this.menuItemArr, (item: string) => {
MenuItem({
content: item === '' ? $r('app.string.system_default') : item,
endIcon: this.fontOffset === item ? $r('app.media.checkmark') : ''
})
.onChange(() => {
this.fontOffset = item;
PreferenceUtils.saveModifyFont(item);
})
}, (item: string) => item)
}
点击系统默认时,fontOffset 设成空字符串,fontFamily 也变成空字符串,字体恢复系统默认。
四、字体大小跟随系统设置
场景咋回事
设置页面点击打开 Toggle 开关,页面字体大小跟随系统设置变化。此时自定义字体大小和字重的 Slider 被禁用,无法滑动或点击。

实现原理
在 app.json5 配置文件里,configuration 标签标识字体大小是否跟随系统。当 fontSizeScale 属性设成 followSystem,且 fontSize 属性用 fp 为单位时,改变系统字体大小缩放比例,应用字体也会变化。
开发步骤
第一步:定义配置文件
在 AppScope/resources/base/profile 下创建 configuration.json:
{
"configuration": {
"fontSizeScale": "followSystem",
"fontSizeMaxScale": "2"
}
}
属性说明:
fontSizeScale: followSystem(跟随系统)或 nonFollowSystem(不跟随系统),默认 nonFollowSystemfontSizeMaxScale: 应用字体相对系统字体的最大比例
第二步:app.json5 引用配置
{
"app": {
"bundleName": "com.example.textdisplayfont",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:layered_image",
"label": "$string:app_name",
"configuration": "$profile:configuration"
}
}
configuration 字段引用 profile 目录下的配置文件。
第三步:Toggle 控制跟随状态
Toggle({ type: ToggleType.Switch, isOn: this.toggleState })
.onChange((isOn: boolean) => {
this.toggleState = isOn;
})
toggleState 为 true 表示跟随系统。
第四步:根据 toggleState 控制 Slider 可交互
Slider({
min: -4,
max: 4,
value: this.fontSizeOffset,
style: SliderStyle.InSet
})
.width('90%')
.margin({ top: 12 })
.enabled(!this.toggleState)
enabled(!this.toggleState):
toggleState为 true(跟随系统),Slider 禁用toggleState为 false(不跟随),Slider 可交互
配置完成后,字体大小和字重随系统设置变化。
五、字体大小不跟随系统设置
场景咋回事
设置页关闭 Toggle 开关,通过 Slider 调整页面字体大小。在系统设置调整字体大小,页面字体不变。
实现原理
app.json5 配置了字体跟随系统设置后,当 fontSize 用屏幕物理像素单位 px 时,页面字体大小不再受系统设置影响。
开发步骤
第一步:fp 转 px 工具函数
用 getDefaultDisplaySync() 获取屏幕实例,取出 densityDPI 物理像素密度。把 fp 数值转成 px:
// Convert fp to px
export function fp2pxUtil(fp: number): string {
const pxStr: string = 'px';
let pxVal: number = 0;
let displayClass: display.Display | null = null;
try {
displayClass = display.getDefaultDisplaySync();
pxVal = fp * (displayClass.densityDPI / 160);
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, TAG, `get densityDPI failed. code: ${error.code}, message:${err.message}`);
}
return pxVal + pxStr;
}
公式:pxVal = fp * (densityDPI / 160)
- densityDPI 是设备物理像素密度
- 160 是基准 DPI
第二步:根据 toggleState 切换字体单位
Text($r('app.string.setting'))
.width('100%')
.fontWeight(700)
.fontSize(this.toggleState ? 26 : fp2pxUtil(26))
toggleState为 true:用 number 类型,单位 fp,字体跟随系统toggleState为 false:调用fp2pxUtil()转 px,字体不跟随系统
六、获取系统缩放比例系数
有时需要获取系统字体缩放比例来手动调整字体大小。
第一步:app.json5 不跟随系统
不配置 configuration 标签,或者 fontSizeScale 设成 nonFollowSystem。
第二步:监听系统环境变化
用 onConfigurationUpdated() 获取缩放比例变化,通过 ApplicationContext.on('environment') 监听:
// System environment change information
let envCallback: EnvironmentCallback = {
onConfigurationUpdated(config) {
envFont.fontSizeScale = config.fontSizeScale; // Font size scaling ratio
envFont.fontWeightScale = config.fontWeightScale; // Font thickness scaling ratio
},
onMemoryLevel(level) {
hilog.info(DOMAIN, TAG, `onMemoryLevel level: ${level}`);
}
}
let appContext = this.context.getApplicationContext();
// Register to monitor changes in the system environment
callbackId = appContext.on('environment', envCallback);
回调里能拿到:
config.fontSizeScale:字体大小缩放比例config.fontWeightScale:字体粗细缩放比例
第三步:手动调整字体大小
基础字体大小 * 缩放系数,传给 fontSize() 属性。
比如基础 20fp,缩放比例 1.5,实际字体大小 = 20 * 1.5 = 30fp。
七、踩坑总结
坑一:字体文件放错位置
字体文件(TTF/OTF)要放在 src/main/resources/rawfile 目录。用 $rawfile('xxx.ttf') 引用。
别放 base 或 dark 目录,那些是颜色、字符串资源目录。
坑二:registerFont 要在页面加载前调用
registerFont() 要在用字体前调用。一般放 aboutToAppear() 里。不然 Text 组件用 fontFamily 找不到注册的字体,显示不出来。
坑三:fontFamily 空字符串是系统默认
fontFamily 设成空字符串,等于不设置,回退到系统默认字体 HarmonyOS Sans。
别以为空字符串会报错或显示异常,它就是默认值。
坎四:fp 和 px 单位区别
- fp(font pixel):跟随系统字体缩放
- px(物理像素):不跟随系统字体缩放
要字体跟随系统就用 fp,不跟随就用 px。
坑五:fontSizeMaxScale 别设太大
fontSizeMaxScale 是应用字体相对系统字体的最大比例。设太大(比如 3 或 4),系统字体调很大时,应用字体可能超出屏幕范围,显示异常。建议设 2。
八、整体流程总结
使用自定义字体:
1. 创建首选项工具类(存取字体数据)
2. EntryAbility 里获取首选项实例
3. 定义 registerFont 方法注册字体
4. 页面加载时注册字体,读取首选项
5. MenuItem 点击时保存字体选择
6. Text 组件 fontFamily 应用字体
字体跟随系统:
1. 定义 configuration.json(fontSizeScale: followSystem)
2. app.json5 引用配置文件
3. Toggle 控制是否跟随
4. Slider 根据状态禁用/启用
字体不跟随系统:
1. fp2px 工具函数转换单位
2. fontSize 根据 toggleState 切换单位
关键点:
registerFont():注册自定义字体fontFamily:空字符串恢复系统默认fontSizeScale: followSystem:跟随系统设置fontSize用 px:不跟随系统设置
更多推荐


所有评论(0)