2. LVGL内置字体详解:内置字体种类、字体大小与风格、内置字体的使用限制
好,咱们进入第二章。上一章我们聊了LVGL字体系统的整体架构,这一章我打算把LVGL内置的那些字体彻底讲透。说白了,内置字体就是你开箱即用、不用额外折腾的那部分字体资源。很多新手上来就急着做自定义字库,结果连内置字体有哪些坑都没摸清楚——嗯,我当年也干过这事儿。
2.1 内置字体有哪些?
LVGL官方维护了一套内置字体,放在 lvgl/src/font/ 目录下。它们都是基于 Montserrat 和 FontAwesome 这两个字体族编译出来的。我个人习惯把它们分成三类:
- 标准字体:Montserrat 的各种字号和风格变体
- 图标字体:FontAwesome 的图标集
- 特殊字体:比如
lv_font_unscii_8这种像素风字体
具体来说,你可以在代码里直接引用的内置字体有这些:
| 字体名称 | 字号(px) | 风格 | 适用场景 |
|---|---|---|---|
lv_font_montserrat_8 |
8 | 常规 | 极小状态栏、角标 |
lv_font_montserrat_10 |
10 | 常规 | 小尺寸标签、辅助文字 |
lv_font_montserrat_12 |
12 | 常规 | 列表项、按钮文字 |
lv_font_montserrat_14 |
14 | 常规 | 正文、对话框内容 |
lv_font_montserrat_16 |
16 | 常规 | 标题、中等强调文字 |
lv_font_montserrat_18 |
18 | 常规 | 大标题、弹窗标题 |
lv_font_montserrat_20 |
20 | 常规 | 主标题、数值显示 |
lv_font_montserrat_22 |
22 | 常规 | 大号数字、强调信息 |
lv_font_montserrat_24 |
24 | 常规 | 时钟、大数值 |
lv_font_montserrat_26 |
26 | 常规 | 超大标题 |
lv_font_montserrat_28 |
28 | 常规 | 超大数值 |
lv_font_montserrat_30 |
30 | 常规 | 极限大字号 |
lv_font_montserrat_32 |
32 | 常规 | 极限大字号 |
lv_font_montserrat_34 |
34 | 常规 | 极限大字号 |
lv_font_montserrat_36 |
36 | 常规 | 极限大字号 |
lv_font_montserrat_40 |
40 | 常规 | 极限大字号 |
lv_font_montserrat_48 |
48 | 常规 | 极限大字号 |
lv_font_montserrat_12_16 |
12 | 常规+16px行高 | 固定行高排版 |
lv_font_montserrat_14_18 |
14 | 常规+18px行高 | 固定行高排版 |
lv_font_montserrat_16_20 |
16 | 常规+20px行高 | 固定行高排版 |
lv_font_montserrat_18_22 |
18 | 常规+22px行高 | 固定行高排版 |
lv_font_montserrat_20_24 |
20 | 常规+24px行高 | 固定行高排版 |
lv_font_montserrat_22_26 |
22 | 常规+26px行高 | 固定行高排版 |
lv_font_montserrat_24_28 |
24 | 常规+28px行高 | 固定行高排版 |
lv_font_montserrat_26_30 |
26 | 常规+30px行高 | 固定行高排版 |
lv_font_montserrat_28_32 |
28 | 常规+32px行高 | 固定行高排版 |
lv_font_montserrat_30_34 |
30 | 常规+34px行高 | 固定行高排版 |
lv_font_montserrat_32_38 |
32 | 常规+38px行高 | 固定行高排版 |
lv_font_montserrat_40_44 |
40 | 常规+44px行高 | 固定行高排版 |
lv_font_montserrat_48_52 |
48 | 常规+52px行高 | 固定行高排版 |
lv_font_unscii_8 |
8 | 像素风 | 复古UI、调试信息 |
lv_font_unscii_16 |
16 | 像素风 | 复古UI、游戏界面 |
lv_font_montserrat_12_16),前一个数字是字号,后一个数字是行高。这在做精确排版时特别有用,我经常在表格和列表里用它们。
2.2 字体大小与风格
你可能会问:为什么LVGL要内置这么多字号?直接给一个通用的,然后缩放不行吗?
原因很简单——LVGL的字体是位图字体,不是矢量字体。每个字号都是预先渲染好的像素点阵,不能像TrueType那样随意缩放。所以你需要什么字号,就得用对应的内置字体文件。
关于风格,内置字体目前只提供了常规(Regular)这一种字重。没有Bold、Italic、Light这些变体。我刚开始用的时候也觉得挺受限的,后来想通了:嵌入式设备资源有限,搞那么多字重,Flash先扛不住了。
不过,LVGL提供了一些字体风格修饰标志,你可以通过 lv_style_set_text_font() 配合 LV_FONT_DECLARE 来切换字体。但注意,这只是换字体文件,不是对同一个字体做风格变换。
lv_style_set_text_opa() 配合描边模拟——但效果嘛,只能说凑合。
2.3 内置字体的使用限制
这部分我得重点说说。内置字体虽然方便,但坑也不少。我在项目里踩过好几次,今天一并给你讲清楚。
2.3.1 字符集限制
内置字体默认只包含 ASCII 字符(0x20-0x7F),外加一些常用的标点和符号。这意味着:
- 不支持中文——一个汉字都没有
- 不支持俄文、阿拉伯文等非拉丁字符
- 不支持扩展拉丁字符,比如 é、ü、ñ 这些
我曾经在一个面向欧洲市场的项目里,直接用内置字体显示德语界面,结果所有的变音符号都显示成了方框。嗯,那场面挺尴尬的。后来老老实实做了自定义字库。
lv_conf.h 中启用了 LV_FONT_MONTSERRAT_12 之类的宏,它只代表这个字体文件被编译进固件,不代表它包含所有字符。字符范围是固定的,改不了。
2.3.2 内存占用
每个内置字体都是一个完整的位图数组,编译后直接放在Flash里。字号越大,占用的Flash空间就越大。我整理了一下大概的数据:
| 字体 | 近似Flash占用 | 包含字符数 |
|---|---|---|
lv_font_montserrat_12 |
~1.2 KB | 95 |
lv_font_montserrat_16 |
~2.8 KB | 95 |
lv_font_montserrat_24 |
~6.5 KB | 95 |
lv_font_montserrat_32 |
~12.3 KB | 95 |
lv_font_montserrat_48 |
~28.6 KB | 95 |
你想想看,如果每个字体都启用,光内置字体就能吃掉你上百KB的Flash。对于Flash只有512KB甚至256KB的MCU来说,这可不是小数目。
2.3.3 无法自定义字符范围
内置字体的字符表是编译时写死的。你不能说「我只想要数字和冒号,其他不要」。要么全要那95个ASCII字符,要么一个都别用。这在做时钟、计数器这类只需要数字的界面时,其实挺浪费的。
2.3.4 抗锯齿效果固定
内置字体默认开启了 4级抗锯齿(即 LV_FONT_ANTIALIAS 为 4)。这在小屏上看着还行,但在大屏或高PPI屏幕上,边缘会有点糊。而且你没法改成8级或关掉抗锯齿——除非你自己重新编译LVGL源码。
2.4 内置字体知识体系
下面这张图帮你把内置字体的核心脉络理清楚:
2.5 什么时候该用内置字体?
根据我自己的项目经验,给你几个判断标准:
- 原型验证阶段:用内置字体快速搭界面,确认布局和交互逻辑
- 纯英文/数字界面:比如仪表盘、计数器、状态指示器
- Flash资源极度紧张:内置字体比自定义字库小得多
- 不需要特殊排版:比如不需要竖排、不需要混合字体