4、样式属性详解(下):文本属性(字体、颜色、对齐、行高)、阴影与轮廓

好,咱们接着聊。上一节我们把背景和边框讲透了,这一节轮到文本和特效了。说实话,文本属性在嵌入式UI里特别容易被忽视——很多人觉得「不就是显示几个字嘛」。但我在项目里吃过不少亏,比如字体没对齐导致界面看起来歪歪扭扭,或者阴影画得太重把性能拖垮了。今天咱们就把这些坑一个个填上。

4.1 文本属性:字体的灵魂三问

LVGL的文本控制,核心就三个东西:用什么字体、什么颜色、怎么对齐。咱们一个一个来。

4.1.1 字体设置:选对字体,事半功倍

字体用 lv_style_set_text_font() 来设置。我个人习惯把字体定义成全局变量,方便复用。

lv_style_set_text_font(&style_btn, &lv_font_montserrat_14);

这里要注意:LVGL的字体是位图字体,不是TrueType。什么意思呢?就是每个字都提前画好了像素点。好处是渲染快,坏处是——你没法随便放大缩小。我曾经在项目里把字体设成24号,结果发现中文字体没包含,显示出来全是方框。嗯,那叫一个尴尬。

避坑指南: 使用中文字体前,务必用字体转换工具(比如LVGL官方的Font Converter)把需要的汉字提前生成好。我曾经因为漏了「确认」两个字,整个按钮标题显示不出来,排查了半天。

4.1.2 文本颜色:不只是好看

颜色设置很简单:

lv_style_set_text_color(&style, lv_color_hex(0x333333));
lv_style_set_text_opa(&style, LV_OPA_80);  // 透明度,80%

但我想多说一句:文本颜色和背景的对比度一定要够。你想想看,如果背景是浅灰色,文字也是浅灰色,用户根本看不清。我一般建议对比度至少4.5:1,这是WCAG无障碍标准的要求。虽然咱们做嵌入式UI不一定非要过认证,但用户体验是实打实的。

4.1.3 文本对齐:左中右,你选哪个?

对齐方式有四种:左对齐、居中对齐、右对齐、两端对齐。用这个宏:

lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);

这里有个细节:对齐是相对于对象的宽度,不是屏幕。比如一个按钮宽200像素,你设了居中对齐,文字就会在按钮中间显示。我见过有人把对齐设成左对齐,但按钮宽度设得特别大,结果文字跑到最左边,看起来像没对齐一样——其实是对齐了,只是对象太宽了。

4.1.4 行高:别让文字挤在一起

行高用 lv_style_set_text_line_space() 控制。默认是0,也就是行与行之间没有额外间距。但多行文本时,我建议至少加4-6像素。

lv_style_set_text_line_space(&style, 6);

为什么?因为汉字本身比较高,如果行间距为0,两行文字几乎贴在一起,阅读体验很差。我在做天气显示界面时,温度、湿度、风速三行信息,加了8像素行高后,整个界面清爽多了。

4.2 阴影:给UI加点立体感

阴影是LVGL 8.0之后才完善的特性。用好了,界面瞬间有层次感;用不好,就是一团糊。

4.2.1 阴影的基本参数

阴影有四个核心参数:

参数 函数 说明
宽度 lv_style_set_shadow_width() 阴影的模糊范围,0表示无阴影
偏移X lv_style_set_shadow_ofs_x() 水平偏移,正数向右
偏移Y lv_style_set_shadow_ofs_y() 垂直偏移,正数向下
颜色 lv_style_set_shadow_color() 阴影颜色,通常用半透明黑

一个典型的按钮阴影设置:

lv_style_set_shadow_width(&style, 10);
lv_style_set_shadow_ofs_x(&style, 2);
lv_style_set_shadow_ofs_y(&style, 4);
lv_style_set_shadow_color(&style, lv_color_hex(0x000000));
lv_style_set_shadow_opa(&style, 30);  // 透明度30%
我的经验: 阴影宽度不要超过对象尺寸的20%。比如一个100x40的按钮,阴影宽度设10-15就够了。设太大不仅难看,还会增加渲染负担——LVGL的阴影是用模糊算法算出来的,宽度越大计算量越大。

4.2.2 阴影的坑:性能与显示

我曾经在一个项目里给每个按钮都加了10像素阴影,结果界面滑动时明显卡顿。后来发现,阴影的模糊计算在低端MCU上很吃资源。解决办法有两个:

  • 减少阴影宽度:5像素以内,性能影响小很多
  • 用图片代替阴影:预渲染一张阴影图片,用 lv_img 显示,完全不消耗CPU

另外要注意:阴影是绘制在对象外部的。如果你的对象紧贴着屏幕边缘,阴影可能会被裁剪掉。我建议给父容器留出至少阴影宽度+偏移量的边距。

4.3 轮廓:另一种「边框」

轮廓(Outline)和边框(Border)很像,但有本质区别:轮廓不占布局空间。什么意思呢?边框会挤占内部内容的空间,但轮廓是画在对象外部的,不影响内部布局。

4.3.1 轮廓的典型用法

轮廓最适合做焦点指示。比如按钮被选中时,加一个轮廓高亮:

lv_style_set_outline_width(&style_focus, 2);
lv_style_set_outline_color(&style_focus, lv_color_hex(0x007AFF));
lv_style_set_outline_pad(&style_focus, 3);  // 轮廓与对象的间距

你看,轮廓和对象之间还有3像素的间距,这样不会和边框重叠。我在做遥控器界面时,就用轮廓来标识当前选中的按钮,效果比改背景色好多了——因为背景色变了会让人觉得按钮「按下了」,而轮廓只是「被选中了」,语义更清晰。

4.3.2 轮廓的注意事项

轮廓有几个限制:

  • 不支持圆角:轮廓始终是直角矩形,即使对象有圆角
  • 不支持单边:要么四边都有,要么都没有
  • 会被父容器裁剪:如果父容器设置了 overflow: hidden,轮廓超出部分会被切掉
避坑指南: 我曾经在列表项上用了轮廓,结果列表滚动时轮廓被父容器裁剪了,看起来像断了一样。后来改用边框+内边距模拟轮廓效果,才解决了这个问题。

4.4 综合示例:一个带阴影和轮廓的卡片

咱们把今天学的串起来,做一个信息卡片:

/* 卡片基础样式 */
lv_style_t style_card;
lv_style_init(&style_card);
lv_style_set_bg_color(&style_card, lv_color_hex(0xFFFFFF));
lv_style_set_radius(&style_card, 8);
lv_style_set_pad_all(&style_card, 16);

/* 阴影:让卡片浮起来 */
lv_style_set_shadow_width(&style_card, 12);
lv_style_set_shadow_ofs_x(&style_card, 0);
lv_style_set_shadow_ofs_y(&style_card, 4);
lv_style_set_shadow_color(&style_card, lv_color_hex(0x000000));
lv_style_set_shadow_opa(&style_card, 25);

/* 标题文本样式 */
lv_style_t style_title;
lv_style_init(&style_title);
lv_style_set_text_font(&style_title, &lv_font_montserrat_16);
lv_style_set_text_color(&style_title, lv_color_hex(0x1A1A1A));
lv_style_set_text_align(&style_title, LV_TEXT_ALIGN_LEFT);

/* 内容文本样式 */
lv_style_t style_content;
lv_style_init(&style_content);
lv_style_set_text_font(&style_content, &lv_font_montserrat_12);
lv_style_set_text_color(&style_content, lv_color_hex(0x666666));
lv_style_set_text_line_space(&style_content, 6);

/* 焦点轮廓样式 */
lv_style_t style_focus;
lv_style_init(&style_focus);
lv_style_set_outline_width(&style_focus, 2);
lv_style_set_outline_color(&style_focus, lv_color_hex(0x007AFF));
lv_style_set_outline_pad(&style_focus, 4);

这个卡片用阴影制造了「浮起」的效果,文本用了不同的字体大小和颜色来区分层级,焦点时还有蓝色轮廓。嗯,基本够用了。

4.5 小结

今天的内容其实就两件事:文本怎么控制特效怎么加。文本方面,字体、颜色、对齐、行高这四个参数,掌握了就能应付90%的场景。阴影和轮廓是锦上添花的东西,但用好了能让UI质感提升一个档次。

最后提醒一句:不要为了特效而特效。我见过有人给每个控件都加阴影,结果界面看起来像一堆纸片堆在一起,反而没有重点。适可而止,才是高手。

下一节咱们讲过渡动画,那才是真正让UI「活」起来的东西。到时候见。