4、内置字体使用:LVGL内置字体(montserrat系列)的启用与配置,字体大小与粗细选择
好,咱们进入第四章。这一章聊点实在的——LVGL 自带的 montserrat 字体到底怎么用。
很多新手一上来就想着搞自定义字体,觉得内置字体不够炫。其实没必要。montserrat 这套字体,LVGL 团队已经帮你优化好了渲染路径,直接用能省不少事。我早期做的一个工业仪表项目,就是全程用 montserrat 系列,跑在 STM32F4 上,帧率稳稳的。
4.1 montserrat 字体家族概览
LVGL 内置的 montserrat 字体,说白了就是一套无衬线西文字体。它覆盖了基本的 ASCII 字符、数字、标点,以及部分拉丁扩展字符。你不需要额外加载任何字体文件,只要在 lv_conf.h 里打开对应的宏就行。
这套字体按粗细和大小分成了多个变体。我整理了一张表,方便你对照选择:
| 宏定义名称 | 像素大小 | 粗细等级 | 适用场景 |
|---|---|---|---|
LV_FONT_MONTSERRAT_8 |
8 px | 常规 | 状态栏、小图标标签 |
LV_FONT_MONTSERRAT_10 |
10 px | 常规 | 紧凑列表项、辅助文字 |
LV_FONT_MONTSERRAT_12 |
12 px | 常规 | 按钮文字、普通标签 |
LV_FONT_MONTSERRAT_14 |
14 px | 常规 | 正文、对话框内容 |
LV_FONT_MONTSERRAT_16 |
16 px | 常规 | 标题、菜单项 |
LV_FONT_MONTSERRAT_18 |
18 px | 常规 | 次级标题 |
LV_FONT_MONTSERRAT_20 |
20 px | 常规 | 主标题 |
LV_FONT_MONTSERRAT_22 |
22 px | 常规 | 大标题、弹窗标题 |
LV_FONT_MONTSERRAT_24 |
24 px | 常规 | 大号数字、强调文字 |
LV_FONT_MONTSERRAT_26 |
26 px | 常规 | 超大标题 |
LV_FONT_MONTSERRAT_28 |
28 px | 常规 | 仪表盘数值 |
LV_FONT_MONTSERRAT_30 |
30 px | 常规 | 特大显示 |
LV_FONT_MONTSERRAT_32 |
32 px | 常规 | 特大显示 |
LV_FONT_MONTSERRAT_34 |
34 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_36 |
36 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_38 |
38 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_40 |
40 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_42 |
42 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_44 |
44 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_46 |
46 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_48 |
48 px | 常规 | 超大数值 |
LV_FONT_MONTSERRAT_12_SUBPX |
12 px | 常规 + 亚像素 | 高DPI屏幕小字 |
LV_FONT_MONTSERRAT_28_COMPRESSED |
28 px | 常规 + 压缩 | Flash紧张的设备 |
LV_FONT_MONTSERRAT_10 到 _48 的 _NORMAL 变体 |
同上 | 常规 | 同上 |
4.2 启用内置字体:lv_conf.h 配置
启用 montserrat 字体,核心就是改 lv_conf.h。找到 LV_FONT_MONTSERRAT 相关的宏,把对应的值从 0 改成 1。
举个例子,你想用 16px 和 24px 的常规字体:
/* lv_conf.h */
#define LV_FONT_MONTSERRAT_16 1 /* 启用 16px 常规 */
#define LV_FONT_MONTSERRAT_24 1 /* 启用 24px 常规 */
编译后,LVGL 会自动把这些字体的位图数据链接进固件。你不需要额外 include 任何头文件,直接通过 &lv_font_montserrat_16 这个指针就能引用。
4.3 字体大小与粗细的选择策略
选字号和粗细,不是拍脑袋决定的。我总结了几条实战经验:
- 阅读距离决定字号: 手持设备(距离 30 cm),12-16 px 足够。车载或工控屏(距离 50-70 cm),建议 18-24 px。如果做的是智能手表,8-12 px 就够,但要注意开启抗锯齿。
- 粗细影响可读性: montserrat 常规体(Normal)的笔画粗细适中,适合正文。但如果你做的是深色背景上的白色文字,常规体可能会显得细。这时候可以考虑用粗体变体——不过 LVGL 内置的 montserrat 没有单独的粗体宏,你需要用
lv_font_set_bold()在运行时加粗,或者自己生成粗体字体。 - 亚像素渲染慎用:
LV_FONT_MONTSERRAT_12_SUBPX这个变体用了亚像素抗锯齿,显示效果更平滑。但它只适用于已知像素排列的 LCD 屏(比如 RGB 条纹排列)。OLED 屏用亚像素反而会有色边。我踩过这个坑,后来老老实实换回常规抗锯齿。
核心原则: 字号越小,越要关注渲染质量。8-12 px 的字体,必须开启抗锯齿(LV_FONT_MONTSERRAT_8 默认带抗锯齿)。14 px 以上可以酌情关闭抗锯齿以提升性能。
4.4 在代码中使用内置字体
启用之后,怎么用?很简单。创建标签或按钮时,直接指定字体指针:
/* 创建一个标签,使用 16px montserrat 字体 */
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_obj_set_style_text_font(label, &lv_font_montserrat_16, 0);
lv_label_set_text(label, "Hello LVGL");
/* 创建一个按钮,使用 24px 字体 */
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_t *btn_label = lv_label_create(btn);
lv_obj_set_style_text_font(btn_label, &lv_font_montserrat_24, 0);
lv_label_set_text(btn_label, "Click Me");
这里有个细节:&lv_font_montserrat_16 这个符号是 LVGL 编译时自动生成的。你不需要自己声明 extern,直接拿来用就行。
4.5 字体选择与性能的权衡
你可能会问:字号越大,渲染越慢,对吧?
对,但不全对。LVGL 的字体渲染性能主要受三个因素影响:
- 字符缓存命中率: 首次绘制一个字符时,LVGL 会解码位图并缓存。后续再画同一个字符,直接从缓存取,速度极快。所以频繁切换字体或使用大量生僻字符,会降低缓存命中率。
- 抗锯齿开销: 开启抗锯齿(默认就是开的),每个字符的渲染时间大约增加 30%-50%。对于 16 px 以下的字体,这个开销值得。对于 24 px 以上的字体,你可以考虑关闭抗锯齿来换性能。
- 字体位图大小: 字号越大,每个字符的位图越大,渲染时内存拷贝的开销也越大。48 px 的字符,渲染时间大约是 16 px 的 6-8 倍。
我个人的建议:如果你的界面需要频繁更新文字(比如实时数据刷新),尽量用 16-20 px 的字体,并保持抗锯齿开启。如果只是静态界面,用大字号也没问题。
4.6 知识体系结构图
下面这张图帮你理清 montserrat 内置字体的使用脉络:
4.7 避坑指南
最后分享几个我踩过的坑:
- 宏没开全: 有一次我开了
LV_FONT_MONTSERRAT_16,但忘了开LV_USE_FONT_MONTSERRAT总开关。编译没报错,但运行时字体显示全是方框。检查了半小时才发现。嗯,这种低级错误,犯一次就记住了。 - 字体指针写错:
&lv_font_montserrat_16中间是下划线,不是连字符。我见过有人写成&lv_font_montserrat-16,编译直接报错。 - Flash 爆了: 曾经在一个 128 KB Flash 的芯片上,一口气开了 8 个字号。编译通过,下载后系统起不来。后来用
map文件一看,字体数据占了 90 KB。从那以后,我养成了先看.map文件再决定开几个字号的习惯。