样式
在 LVGL 中,样式(Style) 是用来控制对象(控件)外观的核心机制,涵盖了 颜色、边框、背景、文字、阴影、渐变、圆角 等视觉特性。通过样式,你可以轻松地为不同状态(如正常、按下、禁用等)指定不同的外观效果。
1. 样式的基本概念
1.1 样式对象(lv_style_t)
- 样式对象中包含若干可配置的视觉属性,例如 背景色、边框宽度、文字颜色、阴影、圆角 等。
- 每个属性都可以通过相关的 API(如
lv_style_set_bg_color()
、lv_style_set_border_width()
)来设置。
1.2 属性类型
- 背景(background):如背景颜色、背景透明度、背景渐变等。
- 边框(border):如边框颜色、边框宽度、边框圆角等。
- 文本(text):如字体、文字颜色、文字对齐方式等。
- 阴影(shadow):如阴影偏移、阴影颜色、阴影宽度等。
- 布局(layout):如内边距(padding)、外边距(margin)等(主要用于布局系统)。
- 轮廓(outline):与边框类似,但通常用于获得“聚焦”效果。
- 其他:如图像(image)、透明度(opa)、转换(transform)等高级属性。
1.3 状态(lv_state_t)
- LVGL 中,每个对象可能处于不同的状态(状态可以组合),如 正常(LV_STATE_DEFAULT)、按下(LV_STATE_PRESSED)、禁用(LV_STATE_DISABLED)、聚焦(LV_STATE_FOCUSED) 等。
- 同一个对象可以在不同状态下应用不同的样式,例如按钮在按下时改变背景色。
1.4 优先级和叠加
- 对象可以同时应用多个样式,这些样式将“叠加”到一起,后添加的样式优先级更高。
- 样式属性可以相互覆盖,例如后添加的样式如果设置了
bg_color
,则会覆盖先前样式的bg_color
。
2. 样式的创建与使用
2.1 创建样式
样式存储在 lv_style_t 变量中。LVGL 的样式系统采用了动态分配与静态分配相结合的方式,目的是尽可能地节省内存。
static lv_style_t style_btn_default;
lv_style_init(&style_btn_default); // 初始化样式,确保处于一个已知的、干净的初始状态
lv_style_set_bg_color(&style_btn_default, lv_color_hex(0x000000));
只存储实际设置的属性
样式(lv_style_t)不会为所有可能的视觉属性预留固定空间,而是仅在需要时,通过动态分配(或扩展已有内存)来存储实际设置的属性值。这避免了为未使用的属性浪费内存。
2.2 给对象添加样式
完成样式初始化后,你可以通过以下方式为对象应用样式:
lv_obj_t *btn = lv_btn_create(lv_scr_act()); // 创建一个按钮对象
lv_obj_add_style(btn, &style_btn_default, LV_STATE_DEFAULT); // 应用于默认状态
- 第三个参数表示应用到哪种状态或场景。传 0 表示应用到 LV_STATE_DEFAULT(即正常、释放的状态)。
2.3 设置不同状态下的样式
如果你想在 按钮按下(PRESSED) 时使用不同的颜色,可以再次创建一个样式用于按下状态:
static lv_style_t style_btn_pressed;
lv_style_set_bg_color(&style_btn, lv_color_hex(0x007ACC)); // 改变背景色
lv_obj_add_style(btn, &style_btn_pressed, LV_STATE_PRESSED); // 应用于按下状态
这样,当按钮处于按下状态时,就会显示新的背景色。
2.4 样式的内存分配
假设你要创建一个按钮样式,只改变背景颜色和圆角属性。初始时,你可能这样写
static lv_style_t style_btn;
lv_style_init(&style_btn); // 初始化样式// 设置背景颜色为红色
lv_style_set_bg_color(&style_btn, lv_color_hex(0xFF0000));// 设置圆角半径为 5 像素
lv_style_set_radius(&style_btn, 5);
实际情况:
- 初始状态
当调用lv_style_init(&style_btn)
时,style_btn.values_and_props
可能为空或分配了一个很小的内存块,因为还没有任何属性被设置。 - 设置背景颜色
当你调用lv_style_set_bg_color(&style_btn, lv_color_hex(0xFF0000));
时,内部会检查这个样式是否已经为背景颜色属性分配了内存。如果没有,它就会分配一个足够存储“背景颜色”这一属性的数据块,然后把属性 ID 和对应的值(红色)存储进去。 - 设置圆角
接下来,调用lv_style_set_radius(&style_btn, 5);
会让系统检查style_btn.values_and_props
是否有足够空间存储另一个属性(圆角)。如果空间不够,系统会动态扩展该内存块,把新的属性和值也存储进去。
这样,只为你真正设置的属性分配内存,而不是预先为所有可能属性保留大量空间。最终,lv_style_t
只占用较小内存,同时能够高效地存储你实际用到的样式属性。这就是 LVGL 为了节省内存而采用动态分配和按需扩展的设计理念。
3. 普通样式和本地样式
3.1 普通样式(共享/常量样式)
普通样式通常是以全局定义的方式存在,常见于主题或默认样式中。这类样式在编译时就已经确定好,并且被多个对象共享,内存开销小,因为它们是只读的。
示例:
static lv_style_t style_btn_default;
lv_style_init(&style_btn_default); // 初始化
lv_style_set_bg_color(&style_btn_default, lv_color_hex(0x000000));
lv_style_set_border_width(&style_btn_default, 2);
3.2 本地样式(Local styles)
当你需要对单个对象进行定制化修改,而不希望影响到其他使用相同普通样式的对象时,LVGL 会为该对象创建一个本地样式副本。
- 修改本地样式不会改变原始的普通样式,因此只会影响当前对象,从而实现个性化的外观设置。
lv_obj_t * btn_local = lv_btn_create(lv_scr_act());
lv_obj_set_style_bg_color(btn_local, lv_color_hex(0xFF5722), LV_PART_MAIN);
lv_obj_set_style_radius(btn_local, 8, LV_PART_MAIN);