一、概述
在LVGL中,样式主要用于设置对象的外观表现,其设计灵感来源于CSS。
-
样式定义:样式是一个 lv_style_t 类型的变量,它可以存储各种属性。类似于CSS中的类,可以集中定义一组样式规则。
-
样式应用:样式可以被分配给对象以改变其外观。在应用时,可以指定目标部分和目标状态。例如,当滑块处于按下状态时,可以为滑块的旋钮部分添加样式。
-
样式复用:一个样式可以被多个对象使用。
-
样式层叠:样式支持层叠效果,即一个对象可以被赋予多个样式。
-
样式优先级:如果一个属性在两个样式中都被定义,则对象将采用最新添加的那个样式的属性值。
-
属性继承:一些属性如果在对象本身没有明确指定,可以从父级对象继承。
-
本地样式:对象还可以拥有优先级高于普通样式的本地样式。本地样式(local styles)是指特定对象(如按钮、标签、图像等)上应用的特定样式设置。这些样式设置将覆盖全局样式,以便在特定对象上实现个性化的外观和行为。
-
与CSS的区别及状态关联:不同于CSS中通过伪类描述不同状态,LVGL直接将属性关联到特定的状态。
在CSS中,伪类用于描述元素的不同状态,例如 :hover 用于鼠标悬停状态,:focus 用于获得焦点状态等。
而在LVGL中,不是通过使用伪类来描述不同的状态,而是将属性分配给特定的状态。举个例子,在LVGL中,可以为对象指定颜色、尺寸等属性,以表示其处于不同的状态,比如按下,释放,选中等状态。这种设计使得在LVGL中更加直接地控制对象的状态。 -
过渡效果:当对象状态发生变化时,可以应用过渡动画效果。
二、样式(lv_style_t)在LVGL中不建议作为局部变量
主要是因为在图形渲染过程中,样式需要持续存在以便于被各个组件引用和使用。当函数执行完毕后,其内部的局部变量会自动销毁,导致分配给样式变量的空间无法再被访问。
LVGL库中的组件可能在创建之后长期存在,并且根据不同的状态或交互来动态切换样式。如果样式是局部变量,在函数执行结束之后就会丢失,那么相关组件就无法再应用之前定义好的样式了。因此,为了确保样式在整个程序运行期间始终可用,建议将其存储为静态、全局或动态分配的内存空间。
二、控件状态与样式
在LVGL中,对象可以处于多种状态的组合,每个状态都有特定的意义:
- 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:红色
如果对象同时聚焦并按下,由于 LV_STATE_PRESSED 优先级高于 LV_STATE_FOCUSED,因此会使用灰色背景。
组合状态优先级为其值相加。如 LV_STATE_PRESSED | LV_STATE_FOCUSED,此组合状态的优先级为 0x0020 + 0x0002 = 0x0022。
若要为所有状态设置相同的属性(例如,红色背景),只需在默认状态下设置即可。
三、组件元素
组件内部可独立设置样式的各个部分(构建复杂组件的基本元素):
- LV_PART_MAIN:表示组件的主要背景部分,通常是一个类似矩形的区域。
- LV_PART_SCROLLBAR:滚动条部分,用于实现组件内容的滚动。
- LV_PART_INDICATOR:指示器部分,例如滑块、进度条、开关或复选框中的勾选框。
- LV_PART_KNOB:旋钮或手柄部分,用户可以通过它来调整数值或位置。
- LV_PART_SELECTED:标记当前选择的选项或区域,如列表项的高亮显示。
- LV_PART_ITEMS:适用于具有多个相似元素的组件,比如表格单元格。
- LV_PART_TICKS:刻度线部分,常见于图表或仪表盘上。
- LV_PART_CURSOR:光标部分,用于标记特定位置,例如文本区域内的插入点或图表上的标记点。
- LV_PART_CUSTOM_FIRST:为自定义组件预留的扩展点,从此值开始的值可用于自定义部件。
- LV_PART_ANY:特殊值,用于某些函数中以匹配所有组件部分,即对整个组件应用样式或操作。
四、样式属性
4.1、尺寸和位置
1、width、height
对象的宽度、高度。
2、min_width、max_width、min_height、max_height
最小、最大宽度和宽度。
3、x、y
对象在屏幕上的X坐标和Y坐标。
4、align
对象在其父容器中的对齐方式。
5、transform_width、transform_height
对象在宽度和高度方向上分别增加指定值,即在两侧加宽或增高。
在LVGL中主要用于在对象的原始尺寸基础上增加额外的视觉尺寸,而不改变其实际占用的空间。这个属性通常在以下场景下使用:
-
创建边框效果:如果想要模拟一个具有内凹或外凸效果的边框,可以设置这两个属性来扩展对象“视觉”尺寸,达到类似阴影、立体边框等效果。
-
过渡动画和视觉变形:在动画过程中,如果需要动态地改变对象的视觉大小但又不更改布局位置或占用的实际空间时,可以利用这两个属性实现尺寸的临时扩展或收缩。
-
装饰性元素增强:对于某些装饰性的UI元素,为了增强视觉表现力,可能需要在元素周围添加一些额外的尺寸以突出显示。
-
响应式设计:虽然LVGL中的响应式设计主要通过布局引擎来实现,但在特定条件下,开发者可能希望根据不同的状态或条件,为组件增加视觉上的延展感。
6、translate_x、translate_y
在X轴和Y轴方向平移对象。
7、transform_zoom
对像图片类对象进行缩放。
仅会修改对象的显示尺寸,而不会修改对象的实际占用空间。
int main(int argc, char **argv)
{
lv_init();
hal_init();
lv_obj_t *window = lv_disp_get_scr_act(NULL);
lv_obj_t * img;
img = lv_img_create(window);
lv_img_set_src(img, "M:bbb.png");
static lv_style_t style_zoom;
lv_style_init(&style_zoom); // 初始化样式
lv_style_set_transform_zoom(&style_zoom, LV_IMG_ZOOM_NONE * 2);
lv_obj_add_style(img, &style_zoom, LV_STATE_DEFAULT);
lv_obj_center(img);
while (1)
{
lv_task_handler();
usleep(5 * 1000);
}
return 0;
}
LV_IMG_ZOOM_NONE 表示正常大小,LV_IMG_ZOOM_NONE * 0.5 表示缩小到0.5倍,LV_IMG_ZOOM_NONE * 2表示放大到2倍。
8、transform_angle
旋转图像类对象。旋转角度是以0.1度为单位递增,例如45度表示为450。
仅会修改对象的显示尺寸,而不会修改对象的实际占用空间。
int main(int argc, char **argv)
{
lv_init();
hal_init();
lv_obj_t *window = lv_disp_get_scr_act(NULL);
lv_obj_t * img;
img = lv_img_create(window);
lv_img_set_src(img, "M:pen.png");
static lv_style_t style_zoom;
lv_style_init(&style_zoom);
lv_style_set_transform_angle(&style_zoom,450);
lv_obj_add_style(img, &style_zoom, LV_STATE_DEFAULT);
lv_obj_center(img);
while (1)
{
lv_task_handler();
usleep(5 * 1000);
}
return 0;
}
4.2、边距
1、pad_top、pad_bottom、pad_left、pad_right
上下左右内边距。
2、pad_row、pad_column
行与行、列与列的间距,在布局中使用时生效。
4.3、背景
1、bg_color
对象的背景颜色。
2、bg_opa
背景颜色的不透明度。可以使用 LV_OPA_TRANSP 至 LV_OPA_COVER 之间的值表示从完全透明到完全不透明的不同程度。
3、bg_grad_color
背景渐变的颜色。仅当 bg_grad_dir 不是 LV_GRAD_DIR_NONE 时有效。
4、bg_grad_dir
背景渐变的方向。
- LV_GRAD_DIR_NONE:无渐变
- LV_GRAD_DIR_HOR:水平渐变
- LV_GRAD_DIR_VER:垂直渐变
5、bg_main_stop、bg_grad_stop
背景颜色和渐变颜色在渐变中的起始点。
数值范围是0-255,0代表顶部/左侧,255代表底部/右侧,128代表中心。
6、bg_img_src
背景图像源,可以是 lv_img_dsc_t 结构体指针、文件路径或预定义的 LV_SYMBOL 图标。
7、bg_img_opa
背景图像的不透明。
8、bg_img_recolor
混合到背景图像上的颜色。
9、bg_img_recolor_opa
背景图像重着色的强度。
10、bg_img_tiled
背景图像是否平铺显示。
4.4、边框
1、border_color
边框的颜色。
2、border_opa
边框的不透明度。
3、border_width
边框的宽度,仅接受像素值作为输入。
4、border_side
边框应该绘制在哪一侧或哪几侧。
- LV_BORDER_SIDE_NONE:无边框
- LV_BORDER_SIDE_TOP:顶部
- LV_BORDER_SIDE_BOTTOM:底部
- LV_BORDER_SIDE_LEFT:左侧
- LV_BORDER_SIDE_RIGHT:右侧
- LV_BORDER_SIDE_INTERNAL:内部边框(可能用于实现内阴影等效果)
可以通过“按位或”运算符 | 将多个选项组合起来指定多条边框。
5、border_post
边框是在子元素绘制之前还是之后绘制。
如果设为 true,则边框会在所有子元素绘制完毕后绘制;设为 false 则相反。
4.5、文本
1、text_color
文本的颜色。
2、text_opa
文本的不透明度。
3、text_font
文本所使用的字体(指向一个 lv_font_t 类型的指针)。
4、text_letter_space
文本字符间的间距,单位为像素。
5、text_line_space
文本行间的间距,像素为单位。
6、text_decor
文本装饰效果,可能的值包括:
- LV_TEXT_DECOR_NONE:无装饰
- LV_TEXT_DECOR_UNDERLINE:下划线
- LV_TEXT_DECOR_STRIKETHROUGH:删除线
通过“按位或”运算符 | 可以组合多个装饰效果。
7、text_align
文本内各行的对齐方式。这仅针对文本内部行的对齐,而非整个文本对象本身的对齐。
可选值包括:
- LV_TEXT_ALIGN_LEFT:左对齐
- LV_TEXT_ALIGN_CENTER:居中对齐
- LV_TEXT_ALIGN_RIGHT:右对齐
- LV_TEXT_ALIGN_AUTO:自动检测文本基向并相应地采用左或右对齐
4.6、图像
1、img_opa
图像的不透明度。
2、img_recolor
混合到图像的颜色。这个属性可以让图像在显示时与指定颜色进行混合,实现类似色彩滤镜的效果。
3、img_recolor_opa
混合颜色的强度。
4.7、轮廓
1、outline_width
轮廓线的宽度(以像素为单位)。
2、outline_color
轮廓的颜色。
3、outline_opa
轮廓线的不透明度。
4、outline_pad
轮廓与对象内容之间的内边距。默认值为0,即轮廓紧贴着对象边缘。
4.8、阴影
1、shadow_width
阴影的宽度(以像素为单位)。
2、shadow_ofs_x
在X轴方向上设置阴影的偏移量(以像素为单位)。
默认值为 0,即阴影紧贴对象底部或右侧(根据方向而定)。
3、shadow_ofs_y
在Y轴方向上设置阴影的偏移量(以像素为单位)。默认值为 0,即阴影在垂直方向上与对象对齐。
4、shadow_spread
控制计算阴影时所依据的基础矩形大小。正值会使阴影区域变大,负值则使之变小。
默认值为 0,即使用原始组件大小作为基础计算阴影。
5、shadow_color
阴影的颜色。默认没有可见的阴影效果。
6、shadow_opa
阴影的不透明度。
4.9、线条
1、line_width
线条的宽度(以像素为单位)。
2、line_dash_width
设置虚线段的宽度(以像素为单位)。虚线功能仅适用于水平线和垂直线。
3、line_dash_gap
设置虚线段之间的间隙(以像素为单位)。
4、line_rounded
线条端点是否圆角化。
5、line_color
线条的颜色。
6、line_opa
线条的不透明度。
4.10、弧形
1、arc_width
设置弧线的宽度(以像素为单位)。
2、arc_rounded
弧线端点是否圆角化。
3、arc_color
弧线的颜色。
4、arc_opa
弧线的不透明度。
5、arc_img_src
设置一个图像源,通过该图像对弧线进行遮罩处理。这有助于在弧线上显示复杂的视觉效果。
输入可以是一个指向 lv_img_dsc_t 结构体的指针,也可以是图片文件的路径。
4.11、其它
1、radius
对象每个角的圆角半径。取值范围:大于等于0的像素值,或者
LV_RADIUS_CIRCLE
表示最大可能的圆角(即完全圆形)。
2、clip_corner
启用或禁用裁剪对象在圆角部分溢出的内容。取值为布尔类型。默认值:0(等同于false)
3、opa
设置对象不透明度。
- 0、
LV_OPA_0
或LV_OPA_TRANSP
表示完全透明。- 256、
LV_OPA_100
或LV_OPA_COVER
表示完全不透明。- 其他值如
LV_OPA_10
、LV_OPA_20
等表示不同程度的半透明。
int main(int argc, char **argv)
{
lv_init();
hal_init();
lv_obj_t *window = lv_disp_get_scr_act(NULL);
lv_obj_t * img;
img = lv_img_create(window);
lv_img_set_src(img, "M:pen.png");
static lv_style_t style_zoom;
lv_style_init(&style_zoom);
lv_style_set_opa(&style_zoom,LV_OPA_50);
lv_obj_add_style(img, &style_zoom, LV_STATE_DEFAULT);
lv_obj_center(img);
while (1)
{
lv_task_handler();
usleep(5 * 1000);
}
return 0;
}
4、color_filter_dsc 和 color_filter_opa
这两个属性共同定义了一个颜色过滤效果。
color_filter_dsc:过滤对象描述。
color_filter_opa:过滤强度。
static lv_color_t my_darken_filter(const lv_color_filter_dsc_t * filter_dsc, lv_color_t color, lv_opa_t opa)
{
return lv_color_darken(color, opa);
}
int main(int argc, char **argv)
{
lv_init();
hal_init();
lv_obj_t *window = lv_disp_get_scr_act(NULL);
lv_obj_t *obj1 = lv_obj_create(window); // 创建一个对象
static lv_style_t style;
lv_style_init(&style);
static lv_color_filter_dsc_t gray_scale_filter_dsc;
gray_scale_filter_dsc.filter_cb = my_darken_filter;
lv_style_set_color_filter_dsc(&style, &gray_scale_filter_dsc);
lv_style_set_color_filter_opa(&style, 200);
lv_style_set_bg_color(&style, lv_color_hex(0x0000FF));
lv_obj_add_style(obj1, &style, LV_PART_MAIN);
lv_obj_center(obj1);
lv_obj_t * img;
img = lv_img_create(window);
lv_img_set_src(img, "M:color.png");
lv_obj_add_style(obj1, &style, LV_PART_MAIN);
lv_obj_align_to(img,obj1 , LV_ALIGN_OUT_LEFT_TOP, 0, -10);
while (1)
{
lv_task_handler();
usleep(5 * 1000);
}
return 0;
}
上面的代码效果是使对象变暗,不过好像对图片没有效果,原因未知。
5、anim_time
动画时长,单位为毫秒。其意义取决于具体的组件,例如文本区域光标闪烁时间或滚轮滚动时间。
6、anim_speed
动画速度,单位为像素/秒。含义根据组件不同而变化,比如标签滚动的速度。
7、transition
一个初始化过的
lv_style_transition_dsc_t
结构体,用于描述对象的过渡效果。
8、blend_mode
指定对象前景色与背景色的混合模式。
LV_BLEND_MODE_NORMAL
:正常混合模式,也称为Alpha混合。根据前景颜色的不透明度(Alpha通道)来混合前景和背景颜色。不透明度为0时完全透明,不显示;不透明度为255时完全不透明,只显示前景色。
int main(int argc, char **argv)
{
lv_init();
hal_init();
lv_obj_t *window = lv_disp_get_scr_act(NULL);
lv_obj_t *obj1 = lv_obj_create(window); // 创建一个对象
static lv_style_t style;
lv_style_init(&style);
lv_style_set_bg_color(&style, lv_color_hex(0x0000FF));
lv_obj_add_style(obj1, &style, LV_PART_MAIN);
lv_obj_set_pos(obj1, 50, 100);
lv_obj_t *obj2 = lv_obj_create(window); // 创建一个对象
static lv_style_t style2;
lv_style_init(&style2);
lv_style_set_bg_color(&style2, lv_color_hex(0xFF0000));
lv_obj_add_style(obj2, &style2, LV_PART_MAIN);
lv_style_set_blend_mode(&style2,LV_BLEND_MODE_NORMAL);
lv_obj_set_pos(obj2, 100, 150);
while (1)
{
lv_task_handler();
usleep(5 * 1000);
}
return 0;
}
- LV_BLEND_MODE_ADDITIVE:在对象渲染时,它会使用颜色加法混合的方式来将对象的颜色与它所在的背景颜色进行混合。具体来说,对于每个像素的 RGB 颜色分量,添加对象的颜色值到背景的颜色值,并将结果裁剪到最大值(255),从而产生一个亮度更高的颜色。这种混合方式常常用于产生发光和光亮效果。
- LV_BLEND_MODE_SUBTRACTIVE:该模式从背景颜色中减去前景颜色的RGB分量。具体来说,对于每个像素的 RGB 颜色分量,将对象的颜色值从背景的颜色值中减去,然后将结果裁剪到最小值(0)。这种混合方式常用于产生阴影、深色效果或者是用于减少光强度的效果。
- LV_BLEND_MODE_MULTIPLY:前景颜色的RGB分量分别与背景颜色的对应分量相乘。对于每个像素的 RGB 颜色分量,将对象的颜色值与背景的颜色值进行乘法操作,然后将结果裁剪到最大值(255)。这种混合方式常常用于产生遮罩效果、颜色叠加效果或者是增强颜色饱和度的效果。
9、layout
对象的布局方式。子元素将根据所设布局策略进行重新定位和大小调整。
10、base_dir
文本或元素的方向性。
- LV_BASE_DIR_LTR:表示文本或元素的基本方向是从左到右。这适用于大多数拉丁字母为基础的书写系统,如英语、西班牙语等。
- LV_BASE_DIR_RTL:表示文本或元素的基本方向是从右到左。这种方向适用于阿拉伯语、希伯来语等以从右到左顺序书写的语言。
- LV_BASE_DIR_AUTO:表示文本或元素的方向可以根据上下文自动调整。
- LV_BASE_DIR_NEUTRAL:表示文本或元素具有中性方向或者没有明确的方向性。
- LV_BASE_DIR_WEAK:表示弱方向性。
五、过渡状态
当LVGL中的一个对象改变其状态(例如,按钮被按下或释放)时,默认情况下会立即应用新状态所关联的属性。即样式上的更改是瞬时完成的。然而,通过使用过渡功能,可以在状态变化时添加动画效果。比如,在按钮被按下时,可以设置背景颜色在300毫秒内逐渐变为按下状态的颜色。
int main(int argc, char **argv)
{
lv_init();
hal_init();
static const lv_style_prop_t trans_props[] =
{
LV_STYLE_BG_OPA, //背景透明度
LV_STYLE_BG_COLOR,//背景颜色
LV_STYLE_PROP_INV /* End marker */
};
static lv_style_transition_dsc_t trans1;
lv_style_transition_dsc_init(&trans1,
trans_props,
lv_anim_path_ease_out,//动画路径函数,用于定义动画的过渡曲线,使用贝塞尔曲线来实现从开头到结尾逐渐加速的效果,呈现了一种先快后慢的过渡曲线。
300, // 过渡持续时间300ms
0, //无延迟
nullptr);
lv_style_t style_nomal;
lv_style_init(&style_nomal);
lv_style_set_bg_color(&style_nomal, lv_palette_main(LV_PALETTE_BLUE)); // 设置常态下的背景色
lv_style_set_bg_opa(&style_nomal, LV_OPA_COVER); // 设置常态下的不透明度
lv_style_set_transition(&style_nomal, &trans1); // 为常态样式添加过渡效果
lv_style_t style_pressed;
lv_style_init(&style_pressed);
lv_style_set_bg_color(&style_pressed, lv_palette_main(LV_PALETTE_RED)); // 设置按下态的背景色
lv_style_set_bg_opa(&style_pressed, LV_OPA_40); // 设置按下的不透明度
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_add_style(btn, &style_nomal, LV_STATE_DEFAULT);
lv_obj_add_style(btn, &style_pressed, LV_STATE_PRESSED);
lv_obj_center(btn);
while (1)
{
lv_task_handler();
usleep(5 * 1000);
}
return 0;
}
六、主题
主题是一个集合概念,它包含了多种样式。当系统中设置了一个激活的主题时,LVGL会自动将这个主题应用到创建的每一个小部件上。这样做的目的是为用户界面(UI)提供一套默认的外观样式。