2-7-1+2_基础对象的样式(styles)

2-7-1+2_基础对象的样式(styles)

知识部分

Styles(风格样式)

Opacity, Blend modes and Transformations(不透明度,混合模式和变换) Cascading styles(层叠样式)

Inheritance(继承) Properties(属性)

Typical background properties(典型的背景属性) Transitions(过渡特效)

Themes (主题)

实践部分

States(状态) Parts(部分)

组合:部分和状态组合

Initialize styles and set/get properties(初始化样式和设置/获取属性) Add and remove styles to a widget(向控件添加和删除样式)

Add styles(添加样式) Replace styles(替换样式) Remove styles(删除样式)

Report style changes(通知样式更改)

Get a property's value on an object(获取对象的属性值) Local styles(本地样式)

知识部分

https://lvgl.100ask.net/9.1/overview/style.html文档位置

Styles(风格样式)

显示原文

"Styles" 用于设置对象的外观。lvgl 中的样式在很大程度上受到CSS的启发。简而言之,其概念如下:

样式是一个 lv_style_t 类型的变量,它可以保存诸如边框宽度、文字颜色等属性。类似于CSS中的 class 。

样式可以分配给对象以改变它们的外观。在分配时,可以指定目标部分(CSS中的伪元素)和目标状态(伪类)。例如,当滑块处于按下状态时,可以将 [ ] (https://lvgl.100ask.net/9.2/overview/style.html#id2)style_blue 样式添加到滑块的旋钮上。

同样的样式可以被任意数量的对象使用。

样式可以进行层叠,这意味着可以将多个样式分配给一个对象,每个样式可以具有不同的属性。因此,并非所有的属性都必须在一个样式中指定。 LVGL将在样式中搜索属性,直到找到定义该属性的样式,或者如果没有任何样式指定,则使用默认值。 例如, style_btn 可以生成默认的灰色按钮,而 style_btn_red 可以仅添加 background-color=red 覆盖背景颜色。

最近添加的样式具有更高的优先级。这意味着,如果一个属性在两个样式中都指定了,对象中最新的样式将被使用。

一些属性(例如文本颜色)如果在对象中未指定,则可以从父对象继承。对象也可以具有局部样式,其优先级高于 “普通” 样式。

与CSS不同(在CSS中,伪类描述不同的状态,例如 :focus ),在LVGL中,属性分配给了给定的状态。

当对象更改状态时,可以应用过渡效果。

Opacity, Blend modes and Transformations(不透明度,混合模式和变换)

OPA = Opacity(不透明度/透明度)

LV_OPA_COVER 表示完全不透明(opacity = 255,完全覆盖)其他常见值:

LV_OPA_TRANSP = 完全透明

LV_OPA_10 = 10% 不透明度

LV_OPA_50 = 50% 不透明度

如果 opa 、 blend_mode 、 transform_angle 或 transform_zoom 属性被设置为它们的非默认值,LVGL将为控件及其所有子级创建一个快照,以便将整个控件与设置的不透明度、混合模式和变换属性混合在一起。

显示原文

这些属性仅在控件的 MAIN 部分上产生作用。

创建的快照称为“中间层”或简称为“层”。如果只有 opa 和/或 blend_mode 设置为非默认值,LVGL可以从较小的块构建图层。这些块的大小可以通过 lv_conf.h 中的以下属性配置:

LV_LAYER_SIMPLE_BUF_SIZE : [字节] 的理想目标缓冲区大小。LVGL将尝试分配此内存大小。

LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE : [字节] 如果无法分配

LV_LAYER_SIMPLE_BUF_SIZE ,则使用该大小。

如果还使用了变换属性,则图层无法以块的形式渲染,而需要分配更大的内存。所需的内存取决于角度、缩放和枢轴参数以及要重绘的区域大小,但永远不会大于控件的大小(包括用于阴影、轮廓等的额外绘制大小)。

如果控件可以完全覆盖要重绘的区域,LVGL将创建一个RGB图层(渲染速度更快,占用的内存更少)。如果相反情况需要使用ARGB渲染。如果控件具有半径、 bg_opa != 255 、有阴影、轮廓等,则控件可能无法覆盖其区域。

控件的点击区域也会相应地进行变换。

Cascading styles(层叠样式)

显示原文

在一个样式中并不需要设置所有的属性。可以给一个对象添加更多的样式,并且后添加的样式可以修改或扩展外观。例如,创建一个通用的灰色按钮样式,然后为红色按钮创建一个新样式,在新样式中只设置新的背景颜色。

这就像在CSS中使用类列表一样,比如 <div class=".btn .btn-red"> 。

后添加的样式具有优先权,优先于先前设置的样式。因此,在上述灰色/红色按钮的例子

中,应该先添加普通按钮样式,然后再添加红色样式。但是,状态的优先级仍然会被考虑。因此,让我们来看一个例子:

基本按钮样式为默认状态设置了暗灰色的颜色,为按下状态设置了浅灰色的颜色

红色按钮样式只在默认状态下将背景颜色设置为红色

在这种情况下,当按钮释放(处于默认状态)时,它将是红色的,因为最近添加的样式(红色样式)完全匹配。当按钮被按下时,浅灰色的颜色更匹配,因为它完美描述了当前的状 态,所以按钮会是浅灰色的。

Inheritance(继承)

显示原文

一些属性(通常与文本相关的属性)可以从父对象的样式中继承。 只有在对象的样式中没有设置给定属性时(即使是默认状态下也是如此),继承才会应用。 在这种情况下,如果属性是可继承的,属性值将在父对象中搜索,直到某个对象为属性指定一个值。 父对象将使用自己的状态来确定值。因此,如果按钮被按下,并且文本颜色来自于这里,那么按下时文本颜色将会被使用。

Properties(属性)

显示原文

点击这里获取完整的样式属性列表 here。

Typical background properties(典型的背景属性)

显示原文

在控件的文档中,您会看到类似于“该控件使用典型的背景属性”的句子。这些“典型的背景属性”包括:

背景

边框

轮廓

阴影

填充

宽度和高度转换

X 和 Y 的平移

Transitions(过渡特效)

默认情况下,当对象改变状态(例如,被按下)时,新状态的新属性立即设置。然而,使用过渡效果可以在状态改变时播放动画。 例如,按下按钮时,它的背景颜色可以在 300 毫秒内动画过渡到按下状态的颜色。

过渡效果的参数存储在样式中。可以设置:

过渡时间

开始过渡前的延迟

动画路径(也称为定时或缓动函数)

要进行动画处理的属性

过渡属性可以为每个状态定义。例如,在默认状态下设置500毫秒的过渡时间意味着当对象进入默认状态时,将应用500毫秒的过渡时间。 在按下状态下设置100毫秒的过渡时间,则在进入按下状态时会有100毫秒的过渡。这个例子的配置意味着迅速进入按下状态,然后慢慢返回默认状态。

为了描述一个过渡,需要初始化一个 lv_transition_dsc_t 变量,并将其添加到一个样式中:

/*Only its pointer is saved so must static, global or dynamically allocated */

static const lv_style_prop_t trans_props[] = 
{

    LV_STYLE_BG_OPA,

    LV_STYLE_BG_COLOR,

    0, /*End marker*/

};

static lv_style_transition_dsc_t trans1; lv_style_transition_dsc_init(&trans1, trans_props, lv_anim_path_ease_out, duration_ms, delay_ms);

lv_style_set_transition(&style1, &trans1);

demo体验: https://docs.lvgl.io/9.1/overview/style.html#transition

http://lvgl.100ask.net/9.1/overview/style.html#transition

Themes (主题)

显示原文

主题是一系列的样式。如果有一个活动主题,LVGL会应用它到每个创建控件上。这将为UI提供一个默认的外观,可以通过添加更多样式来进行修改。

每个显示器可以有不同的主题。例如,你可以在TFT上有一个多彩的主题,在第二个单色显示器上有一个单色的主题。

要为显示器设置一个主题,需要两个步骤:

  1. 初始化一个主题
  2. 将初始化的主题分配给一个显示器。

主题初始化函数可以有不同的原型。下面的例子显示了如何设置“默认”主题:

lv_theme_t * th = lv_theme_default_init(display, /*使用该显示器的 DPI、大小等*/

LV_COLOR_PALETTE_BLUE,

LV_COLOR_PALETTE_CYAN, /*主色和辅助色板*/

false, /*亮或暗模式*/ &lv_font_montserrat_10,&lv_font_montserrat_14, &lv_font_montserrat_18); /*小、正常、大字体*/

lv_display_set_theme(display, th); /*将主题分配给显示器*/

包含的主题在 lv_conf.h 中已启用。如果默认主题由 LV_USE_THEME_DEFAULT 启用,

LVGL在创建显示器时会自动初始化和设置它。 demo体验:

https://docs.lvgl.io/9.1/overview/style.html#extending-the-current-theme http://lvgl.100ask.net/9.1/overview/style.html#extending-the-current-theme

实践部分

States(状态)

显示原文

对象可以处于以下状态的组合中:

LV_STATE_DEFAULT :(0x0000) 正常、释放的状态

LV_STATE_CHECKED :(0x0001) 切换或选中的状态

LV_STATE_FOCUSED :(0x0002) 通过键盘或编码器聚焦,或通过触摸板/鼠标点击

LV_STATE_FOCUS_KEY :(0x0004) 仅通过键盘或编码器聚焦,而非通过触摸板/鼠标

LV_STATE_EDITED :(0x0008) 由编码器编辑

LV_STATE_HOVERED :(0x0010) 鼠标悬停

LV_STATE_PRESSED :(0x0020) 被按下的状态 LV_STATE_SCROLLED :(0x0040) 正在滚动的状态 LV_STATE_DISABLED :(0x0080) 禁用的状态

LV_STATE_USER_1 :(0x1000) 自定义状态 LV_STATE_USER_2 :(0x2000) 自定义状态 LV_STATE_USER_3 :(0x4000) 自定义状态 LV_STATE_USER_4 :(0x8000) 自定义状态

对象可以处于多个状态的组合中,例如同时处于聚焦和按下状态。这被表示为

LV_STATE_FOCUSED | LV_STATE_PRESSED

样式可以应用于任何状态或状态组合。例如,为默认和按下状态设置不同的背景颜色。 如果某个状态中未定义属性,则会使用与之最匹配的状态的属性。通常情况下,这意味着将使用带有 LV_STATE_DEFAULT 的属性。 如果即使对于默认状态,某个属性也未设置,则将使用默认值。(稍后会详细说明)

但是,“与之最匹配的状态的属性”到底是什么意思呢?状态有一个优先级,由它们的值表示

(请参见上面的列表)。值越高,优先级越高。 为了确定使用哪个状态的属性,我们来看一个例子。假设背景颜色定义如下:

LV_STATE_DEFAULT :白色

LV_STATE_PRESSED :灰色

LV_STATE_FOCUSED :红色

  1. 初始情况下,对象处于默认状态,所以情况很简单:属性在对象当前状态中完全定义为白色。
  2. 当对象被按下时,有两个相关属性:白色的默认属性(默认与每个状态相关)和灰色的按下属性。按下状态的优先级为0x0020,高于默认状态的优先级0x0000,因此会使用灰色。
  3. 当对象处于聚焦状态时,与按下状态发生的情况相同,将使用红色。(聚焦状态的优先级高于默认状态)
  4. 当对象处于聚焦和按下状态时,灰色和红色都可以。但是按下状态的优先级高于聚焦状态,因此会使用灰色。
  5. 可以为 LV_STATE_PRESSED | LV_STATE_FOCUSED 设置玫瑰色,此组合状态的优先级为0x0020 + 0x0002 = 0x0022,高于按下状态的优先级,因此将使用玫瑰色。
  6. 当对象处于选中状态时,没有属性来设置此状态的背景颜色。由于缺乏更好的选择,对象仍然保持默认状态的白色属性。

一些实用的注意事项:

状态的优先级(值)非常直观,这是用户自然期望的结果。例如,如果对象处于聚焦状态,用户仍然希望看到它是否被按下,因此按下状态具有更高的优先级。如果聚焦状态具有更高的优先级,它将覆盖按下的颜色。

如果要为所有状态(例如红色背景颜色)设置属性,只需为默认状态设置即可。如果对象在其当前状态下找不到属性,它将退回到默认状态的属性。

使用 OR 运算符来描述复杂情况下的属性(例如,按下 + 选中 + 聚焦)。

对于不同的状态,使用不同的样式元素可能是个好主意。例如,为释放、按下、选中 + 按下、聚焦、聚焦 + 按下、聚焦 + 按下 + 选中等状态找到背景颜色是相当困难的。相反,例如,使用按下和选中状态的背景颜色,并使用不同的边框颜色指示聚焦状态。

lv_style_init(&style_indicator); lv_style_set_bg_opa(&style_indicator, LV_OPA_COVER); lv_style_set_bg_color(&style_indicator,

lv_palette_main(LV_PALETTE_RED/*LV_PALETTE_CYAN*/)); 
lv_style_set_radius(&style_indicator, LV_RADIUS_CIRCLE);
lv_style_set_transition(&style_indicator,&transition_dsc);

/* LV_STATE_PRESSED按下操作*/ lv_obj_add_style(slider, &style_indicator,

LV_STATE_PRESSED);

Parts(部分)

显示原文

物体可以由具有自己样式的“部分”组成。在LVGL中,存在以下预定义部分:

LV_PART_MAIN :像矩形一样的背景

LV_PART_SCROLLBAR :滚动条(们)

LV_PART_INDICATOR :指示器,例如用于滑块、条形图、开关或复选框的勾选框

LV_PART_KNOB :像把手一样用来调节值

LV_PART_SELECTED :表示当前选择的选项或部分

LV_PART_ITEMS :如果控件具有多个类似元素(例如表格单元格)时使用

LV_PART_CURSOR :标记特定位置,例如文本区域或图表的光标

LV_PART_CUSTOM_FIRST :可以从这里开始添加自定义部分标识符。例如,一个 滑动条 具有三个部分:

背景

指示器

把手

这意味着滑动条的这三个部分都可以有自己的样式。稍后我们将看到如何向对象和部分添加样式。

根据2.7.1的代码

lv_style_init(&style_indicator); 
lv_style_set_bg_opa(&style_indicator, LV_OPA_COVER); 
lv_style_set_bg_color(&style_indicator,

lv_palette_main(LV_PALETTE_RED/*LV_PALETTE_CYAN*/));

lv_style_set_radius(&style_indicator, LV_RADIUS_CIRCLE);
lv_style_set_transition(&style_indicator,&transition_dsc);

/* LV_PART_INDICATOR设置类似*/ 
lv_obj_add_style(slider, &style_indicator,

LV_PART_INDICATOR);

组合:部分和状态组合

Part(部件)和 State(状态)的组合。

LV_PART_INDICATOR | LV_STATE_PRESSED

这是 位掩码(bitmask) 的组合方式。| 是按位或运算符,用来同时指定:

哪个部件(Part)

什么状态(State)

lv_style_init(&style_pressed_color); lv_style_set_bg_color(&style_pressed_color, lv_palette_darken(LV_PALETTE_CYAN, 2));

lv_obj_add_style(slider, &style_pressed_color, LV_PART_INDICATOR | LV_STATE_PRESSED); // 当指针部分被按下的时候,指针部分应用该样式

按位或既可以保证状态又可以保证部分

上图就是示例代码运行的结果就是我按下时且我的部分(这里为指示器

[LV_PART_INDICATOR])都为青色。

Initialize styles and set/get properties(初始化样式和设置/获取属性)

样式存储在 lv_style_t 类型的变量中。样式变量应该是静态的、全局的或者动态分配的。 换句话说,它们不能是函数内部的局部变量,在函数结束时会被销毁。 在使用样式之前,应该使用 lv_style_init(&my_style) 进行初始化。样式初始化后,可以添加或更改属性。

属性设置函数的格式如下: lv_style_set_<property_name>(&style, )。例如:

要删除一个属性,可以使用:

static lv_style_t style_btn; lv_style_init(&style_btn);

lv_style_set_bg_color(&style_btn, lv_color_hex(0x115588));//设置背景颜色

lv_style_set_bg_opa(&style_btn, LV_OPA_50);//设置不透明度 
lv_style_set_border_width(&style_btn, 2);//设置 
lv_style_set_border_color(&style_btn, lv_color_black());

static lv_style_t style_btn_red; lv_style_init(&style_btn_red);

lv_style_set_bg_color(&style_btn_red, lv_palette_main (LV_PALETTE_RED));

lv_style_set_bg_opa(&style_btn_red, LV_OPA_COVER);

lv_style_remove_prop(&style, LV_STYLE_BG_COLOR);

从样式中获取属性的值:

lv_style_value_t v;

lv_res_t res = lv_style_get_prop(&style, LV_STYLE_BG_COLOR, &v); 
if(res == LV_RES_OK) { /*找到了*/

do_something(v.color);

}

lv_style_value_t 包含 3 个字段:

num:用于整数、布尔值和不透明度属性 color:用于颜色属性 ptr:用于指针属性

要重置一个样式(释放其所有数据),可以使用:

lv_style_reset(&style);

样式也可以定义为 const,以节省 RAM:

以后可以像其他样式一样使用 const 样式,但显然不能添加新属性。

const lv_style_const_prop_t style1_props[] = { LV_STYLE_CONST_WIDTH(50), LV_STYLE_CONST_HEIGHT(50), LV_STYLE_CONST_PROPS_END};

LV_STYLE_CONST_INIT(style1, style1_props);

Add and remove styles to a widget(向控件添加和删除样式)

显示原文

一个单独的样式并不是特别有用,必须将其分配给一个对象才能生效。

Add styles(添加样式)

显示原文

为了给对象添加样式,请使用 lv_obj_add_style(obj, &style, <selector>) 。 <selector> 是一个按位或运算的值,用于指定要添加样式的部分和状态。下面是一些示例:

LV_PART_MAIN | LV_STATE_DEFAULT

LV_STATE_PRESSED :按下状态下的主要部分。可以省略 LV_PART_MAIN

LV_PART_SCROLLBAR :默认状态下的滚动条部分。可以省略 LV_STATE_DEFAULT

LV_PART_SCROLLBAR | LV_STATE_SCROLLED:当对象被滚动时的滚动条部分。

LV_PART_INDICATOR | LV_STATE_PRESSED | LV_STATE_CHECKED:对象被按下和选中时的指示器部分。

使用 lv_obj_add_style()

lv_obj_add_style(btn, &style_btn, 0); lv_obj_add_style(btn, &btn_red, LV_STATE_PRESSED);

改为红色*/

/*默认按钮样式*/

/*仅在按下时将部分颜色更

Replace styles(替换样式)

显示原文

使用下列语句来替换对象的特定样式:lv_obj_replace_style(obj, old_style, new_style, selector)。 此函数仅在 selector 匹配 lv_obj_add_style 中使用的 selector 时,才会将 old_style 替换为 new_style 。 两种样式,即 old_style 和 new_style 都不能为 NULL (添加和删除分别存在不同的函数)。 如果 obj 的样式中存在多个 old_style 和 selector 的组合,所有出现的情况都将被替换。函数的返回值指示是否至少进行了一次成功替换。

使用 lv_obj_replace_style()

lv_obj_add_style(btn, &style_btn, 0); /* 添加按钮样式 */ lv_obj_replace_style(btn, &style_btn, &new_style_btn, 0); /* 用不同的样式替换按钮样式 */

Remove styles(删除样式)

显示原文

从对象中删除所有样式,请使用 lv_obj_remove_style_all(obj)。

要删除特定的样式,请使用 lv_obj_remove_style(obj, style, selector)。 此函数将仅在 selector 与

lv_obj_add_style() 中使用的 selector 匹配时删除 style 。 style 可以是 NULL ,以仅检查 selector 并删除所有匹配的样式。 selector 可以使用 LV_STATE_ANY LV_PART_ANY 值,从任何状态或部件中删除样式。

Report style changes(通知样式更改)

显示原文

如果已经分配给一个对象的样式发生改变(例如添加或更改属性),那么使用该样式的对象应该收到通知。有三种选项可以做到这一点:

  1. 如果你知道改变的属性可以通过简单的重绘来应用(例如颜色或不透明度的变化),只需调用: lv_obj_invalidate(obj) 或者 lv_obj_invalidate(lv_screen_active())。
  2. 如果更改或添加了更复杂的样式属性,并且你知道哪些对象受到该样式的影响,请调用: lv_obj_refresh_style(obj, part, property)。要刷新所有部件和属性,请使用: lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY)。
  3. 要让LVGL检查所有对象以查看它们是否使用了样式,并在需要时刷新它们,请调用:

lv_obj_report_style_change(&style)。如果 style 是 NULL,则所有对象将收到有关样式更改的通知。

Get a property's value on an object(获取对象的属性值)

显示原文

获取物体的最终属性值

考虑层叠、继承、本地样式和过渡效果(见下文)

可以使用此类属性获取函数: lv_obj_get_style_<property_name>(obj, <part>) 。 这些函数使用物体的当前状态,如果没有更好的候选项,则返回默认值。 例如:

lv_color_t color = lv_obj_get_style_bg_color(btn, LV_PART_MAIN);

Local styles(本地样式)

显示原文

除了“普通”样式外,对象还可以存储本地样式。 这个概念类似于CSS中的内联样式(例如 <div style="color:red"> ),但有一些修改。

函数对比一般加obj即为本地样式

/*本地样式*/

lv_obj_set_style_bg_color(slider, lv_color_red(), LV_PART_INDICATOR | LV_STATE_FOCUSED);

/*普通样式*/

lv_style_set_bg_color(&style_btn, lv_color_hex(0x115588));

本地样式与普通样式类似,但不能在其他对象之间共享。如果使用,本地样式会自动分配,并且在对象被删除时释放。它们很适合为对象添加本地定制。

与CSS不同,LVGL中的本地样式可以分配给状态( 伪类)和部分( 伪元素)。

要设置本地属性,请使用如下函数: lv_obj_set_style_<property_name>(obj, <value>,

<selector>); 例如:

lv_obj_set_style_bg_color(slider, lv_color_red(), LV_PART_INDICATOR | LV_STATE_FOCUSED);

posted @ 2026-07-30 17:55  哲别羽  阅读(1)  评论(0)    收藏  举报