Positions, sizes, and layouts(位置、大小和布局)
Units(单位)
1、pixel:像素位置,整数始终表示像素。
lv_obj_set_x(btn, 10);
2、percentage: 控件或其父控件大小的百分比,lv_pct(value) 将一个值转换为百分比。
lv_obj_set_width(btn,lv_pct(50));
3、LV_SIZE_CONTENT: 设置控件宽度/高度为包含所有子控件的特殊值。
lv_obj_set_width(btn, LV_SIZE_CONTENT);
存在内边距的计算
lv_obj_set_x(obj, 10);
lv_obj_set_y(obj, 20);
默认情况下,x和y坐标是从父对象的内容区域的左上角开始计算的。例如,如果父对象的每一边都有五个像素的内边距(padding),那么上面的代码会把 obj 放置在(15, 25),因为内容区域在填充之后开始计算。
百分比值是通过父对象的内容(content)区域的大小来计算的。
lv_obj_set_x(btn, lv_pct(10)); //x = 父元素内容区域宽度的10%
Alignment(对齐)
1、改变对齐方式(对象内部对齐)
lv_obj_set_align(obj, align);
如果父对象的大小改变,则子对象的设置对齐和位置会根据父对象的变化自动调整更新。
2、改变对齐方式(对象外部对齐)
lv_obj_align_to(label, btn, LV_ALIGN_OUT_TOP_MID, 0, -10);
lv_obj_align_to() 不能
在对象的坐标或参考对象的坐标发生变化时重新对齐对象.
3.获取边界框的大小:
获取对象的外部宽度(包括边框、阴影等装饰部分的总宽度 )
int32_t w = lv_obj_get_width(obj);
int32_t h = lv_obj_get_height(obj);
4.获取内容区域的大小:
获取对象的内容区域宽度,即去除边框、外边距、内边距(padding ,若有设置)等装饰后,实际可用于显示内容(如文本、图片等)的水平空间宽度 。
int32_t content_w = lv_obj_get_content_width(obj);
int32_t content_h = lv_obj_get_content_height(obj);
Translation(位置转换)
在按下按钮时将按钮上移一点。推荐可以使用平移。
void translation(){// 样式初始化(确保只执行一次)static lv_style_t style_normal;static lv_style_t style_pressed;static lv_style_t style_pressed2;static bool styles_inited = false;if (!styles_inited) {lv_style_init(&style_normal);lv_style_set_y(&style_normal, 100); // 正常状态:Y轴偏移100lv_style_init(&style_pressed);lv_style_set_translate_y(&style_pressed, -20);lv_style_init(&style_pressed2);lv_style_set_transform_width(&style_pressed2, 10);lv_style_set_transform_height(&style_pressed2, 10);styles_inited = true;}// 创建屏幕screen = lv_obj_create(NULL);lv_scr_load(screen);//位置转换(平移)// 创建 btn1(不设置固定Y坐标,由样式控制)btn1 = lv_btn_create(screen);lv_obj_set_height(btn1, 100);lv_obj_set_width(btn1, 150);lv_obj_set_x(btn1, 100); // 只设置X坐标,Y坐标由样式控制lv_obj_set_style_bg_color(btn1, lv_color_hex(0xFFEEFF), LV_PART_MAIN);// 应用样式(关键:正常状态和按下状态的Y偏移)lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);//大小转换btn2 = lv_btn_create(screen);lv_obj_set_width(btn2, 100);lv_obj_set_height(btn2, 100);lv_obj_set_x(btn2, 300);lv_obj_set_y(btn2, 100); lv_obj_set_style_bg_color(btn2, lv_color_hex(0x808000), LV_PART_MAIN);lv_obj_add_style(btn2,&style_pressed2,LV_STATE_PRESSED);
}
Transformation(大小转换)
1.变换后的宽度和高度会分别加在对象的两侧。这意味着,一个 10 像素的变换宽度会使对象宽 20 像素(两侧各增加 10 像素)。
2.与位置平移不同,大小转换并不会使对象“真正”变大。换句话说,滚动条、布局和 LV_SIZE_CONTENT 不会对变换后的大小做出反应。因此,大小转换 “只是” 一种视觉效果。
void translation(){// 样式初始化(确保只执行一次)static lv_style_t style_normal;static lv_style_t style_pressed;static lv_style_t style_pressed2;static bool styles_inited = false;if (!styles_inited) {lv_style_init(&style_normal);lv_style_set_y(&style_normal, 100); // 正常状态:Y轴偏移100lv_style_init(&style_pressed);lv_style_set_translate_y(&style_pressed, -20);lv_style_init(&style_pressed2);lv_style_set_transform_width(&style_pressed2, 10);lv_style_set_transform_height(&style_pressed2, 10);styles_inited = true;}// 创建屏幕screen = lv_obj_create(NULL);lv_scr_load(screen);//位置转换(平移)// 创建 btn1(不设置固定Y坐标,由样式控制)btn1 = lv_btn_create(screen);lv_obj_set_height(btn1, 100);lv_obj_set_width(btn1, 150);lv_obj_set_x(btn1, 100); // 只设置X坐标,Y坐标由样式控制lv_obj_set_style_bg_color(btn1, lv_color_hex(0xFFEEFF), LV_PART_MAIN);// 应用样式(关键:正常状态和按下状态的Y偏移)lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);//大小转换btn2 = lv_btn_create(screen);lv_obj_set_width(btn2, 100);lv_obj_set_height(btn2, 100);lv_obj_set_x(btn2, 300);lv_obj_set_y(btn2, 100); lv_obj_set_style_bg_color(btn2, lv_color_hex(0x808000), LV_PART_MAIN);lv_obj_add_style(btn2,&style_pressed2,LV_STATE_PRESSED);
}
Min and Max size(最小和最大尺寸)
1、限制了对象的大小,防止其变得比这些值更小/更大。
static lv_style_t style_max_height;
lv_style_init(&style_max_height);
lv_style_set_y(&style_max_height, 200);lv_obj_set_height(obj, lv_pct(100));
lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //将高度限制为200像素
2、使用百分比值,相对于父对象的内容区域的大小。
static lv_style_t style_max_height;
lv_style_init(&style_max_height);
lv_style_set_y(&style_max_height, lv_pct(50));lv_obj_set_height(obj, lv_pct(100));
lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //将高度限制为父容器高度的一半
Layout(布局)
1、布局可以更新对象子对象的位置和大小。它们可以用于自动排列子对象成一行或一列,或者以更复杂的形式排列。
2、布局设置的位置和大小会覆盖“正常”的x、y、宽度和高度设置。
3、每个布局都有一个相同的函数: lv_obj_set_layout(obj, <布局名称>) 用于在对象上设置布局。
内置布局
LVGL带有两种非常强大的布局:
1、Flexbox:将对象排列成行或列,支持换行和扩展项目。
2、Grid:在二维表中将对象排列成固定位置。
Flags(标志)
有一些标志可以用于对象,以影响它们与布局的行为:
LV_OBJ_FLAG_HIDDEN
隐藏的对象在布局计算中被忽略。
LV_OBJ_FLAG_IGNORE_LAYOUT
该对象被布局简单地忽略。它的坐标可以像常规那样设置。
LV_OBJ_FLAG_FLOATING
与 LV_OBJ_FLAG_IGNORE_LAYOUT
相同,但具有 LV_OBJ_FLAG_FLOATING
标志的对象将在 LV_SIZE_CONTENT
计算中被忽略。
这些标志可以使用 lv_obj_add_flag(obj, FLAG)
和lv_obj_remove_flag(obj, FLAG)
添加/移除。
移除某个标志:lv_obj_clear_flag(obj,FLAG);
Order of Creation(图层顺序)
1、默认情况下,LVGL会将新的Widgets绘制在旧的Widgets之上。
例如,假设我们在名为button1的父Widget上添加一个按钮,然后再添加另一个名为button2的按钮。那么,button1(及其子Widget)将处于背景中,并可能被button2及其子Widget覆盖。
void OrderOfCreation(){/* 创建一个屏幕 */screen = lv_obj_create(NULL);lv_scr_load(screen); /* 加载屏幕 *//* 创建两个按钮 */lv_obj_t * btn1 = lv_btn_create(screen); /* 在屏幕上创建一个按钮 */lv_obj_set_size(btn1, 100, 60); lv_obj_set_pos(btn1, 80, 100); /* 设置按钮的位置 */lv_obj_t * btn2 = lv_btn_create(screen); lv_obj_set_size(btn2, 100, 60); lv_obj_set_pos(btn2, 150, 100); /* 为按钮添加标签 */lv_obj_t * label1 = lv_label_create(btn1); /* 在按钮1上创建标签 */lv_label_set_text(label1, "Button 1"); /* 设置标签文本 */lv_obj_t *label2 = lv_label_create(btn2); /* 在按钮2上创建标签 */lv_label_set_text(label2, "Button 2"); /* 设置标签文本 */
}
Styles(风格样式)
1、样式是一个 lv_style_t 变量,它可以保存边框宽度、文本颜色等属性。它类似于 CSS 中的“类”。
2、可以将样式分配给对象以更改其外观。在赋值过程中,可以指定目标部分(CSS 中的pseudo element)和目标状态(pseudo class)。例如,当滑块处于按下状态时,可以将“style_blue”添加到滑块的旋钮。
3、任何数量的对象都可以使用相同的样式。
4、样式可以级联,这意味着可以将多个样式分配给一个对象,并且每个样式可以具有不同的属性。因此,并非所有属性都必须在样式中指定。 LVLG 将寻找一个属性,直到一个样式定义它,或者如果它没有被任何样式指定,则使用默认值。例如,style_btn 可以导致默认的灰色按钮,而style_btn_red 只能添加一个background-color=red 来覆盖背景颜色。
5、后来添加的样式具有更高的优先级。这意味着如果在两种样式中指定了一个属性,则将使用稍后添加的样式。
6、如果对象中未指定某些属性(例如文本颜色),则可以从父级继承。
7、对象可以具有比“正常”样式具有更高优先级的本地样式。具体解释如下:
- “正常” 样式:通常指全局样式(通过
lv_style_create
创建,可被多个对象共享),例如为所有按钮设置统一的默认背景色。 - 本地样式:直接绑定到单个对象的样式(通过
lv_obj_add_style
给特定对象添加),仅对该对象生效。 - 优先级规则:本地样式的优先级 高于 全局样式。当两者设置了相同属性(如背景色)时,会优先使用本地样式的配置。
8、当对象改变状态时可以应用转换。具体解释如下:
状态转换:指对象从一个状态切换到另一个状态时(如从默认状态 → 按下状态),样式变化可以通过动画过渡实现,而不是瞬间切换。
Status(状态)
对象可以处于以下状态的组合:
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_FOCUSED | LV_STATE_PRESSED。
样式可以添加到任何状态和状态组合。 例如,为默认和按下状态设置不同的背景颜色。 如果属性未在状态中定义,则将使用 最佳匹配状态的属性 。通常这意味着使用带有 LV_STATE_DEFAULT 的属性。 如果是默认状态但是没有设置他的属性,那么将会使用默认值。
但是 “最佳匹配状态的属性” 到底是什么意思呢? 状态具有优先级,由它们的值显示(参见上面的列表)。更高的值意味着更高的优先级。 为了确定使用哪个状态的属性,让我们举个例子。想象一下,背景颜色是这样定义的:
LV_STATE_DEFAULT
:白色
LV_STATE_PRESSED
:灰色
LV_STATE_FOCUSED
:红色
1.默认情况下,对象处于默认状态,所以这是一个简单的情况:属性在对象当前状态下完美定义为白色。
2. 当对象被按下时有2个相关属性:默认为白色(默认与每个状态相关)和按下为灰色。 按下状态的优先级为 0x0020,高于默认状态的 0x0000 优先级,因此将使用灰色。
3. 当物体聚焦时,发生与按下状态相同的事情,将使用红色。 (焦点状态比默认状态具有更高的优先级)。
4. 当物体聚焦并按下时,灰色和红色都可以工作,但按下状态的优先级高于聚焦状态,因此将使用灰色。
5. 可以为 LV_STATE_PRESSED | LV_STATE_FOCUSED 设置例如玫瑰色。 。 在这种情况下,此组合状态的优先级为 0x0020 + 0x0002 = 0x0022,高于按下状态的优先级,因此将使用玫瑰色。
6. 当对象处于选中状态时,没有设置此状态的背景颜色的属性。因此,由于缺乏更好的选择,对象从默认状态的属性中保持白色。
一些实用的注意事项:
1、状态的优先级(值)非常直观,这是用户自然期望的。例如。如果一个对象被聚焦,用户仍然希望查看它是否被按下,因此按下状态具有更高的优先级。 如果聚焦状态具有更高的优先级,它将覆盖按下的颜色。
效果
:
仅聚焦时:显示黄色(聚焦样式)。
聚焦 + 按下时:显示红色(按下样式覆盖聚焦,符合用户预期)。
// 定义样式static lv_style_t style_default; // 默认状态(无特殊状态)static lv_style_t style_focused; // 聚焦状态static lv_style_t style_pressed; // 按下状态lv_style_init(&style_default);lv_style_set_bg_color(&style_default, lv_color_hex(0xFFFFFF)); // 白色lv_style_init(&style_focused);lv_style_set_bg_color(&style_focused, lv_color_hex(0xFFFF00)); // 黄色(聚焦)lv_style_init(&style_pressed);lv_style_set_bg_color(&style_pressed, lv_color_hex(0xFF0000)); // 红色(按下)// 创建按钮并绑定状态lv_obj_t *btn = lv_btn_create(screen);lv_obj_set_size(btn,50,30);lv_obj_set_pos(btn,80,50);lv_obj_add_style(btn, &style_default, LV_STATE_DEFAULT);lv_obj_add_style(btn, &style_focused, LV_STATE_FOCUSED); // 聚焦状态lv_obj_add_style(btn, &style_pressed, LV_STATE_PRESSED); // 按下状态(优先级更高)
2、如果您想为所有状态设置一个属性(例如红色背景色),只需将其设置为默认状态即可。如果对象找不到当前状态的属性,它将回退到默认状态的属性。
效果
:
默认状态:白色背景 + 2px 边框。
按下状态:红色背景(自定义) + 2px 边框(继承默认状态,因为按下状态没有定义边框)。
static lv_style_t style_default;static lv_style_t style_pressed;lv_style_init(&style_default);lv_style_set_bg_color(&style_default, lv_color_hex(0xFFFFFF)); // 白色(默认)lv_style_set_border_width(&style_default, 2); // 边框宽度2px(所有状态通用)lv_style_init(&style_pressed);lv_style_set_bg_color(&style_pressed, lv_color_hex(0xFF0000)); // 红色(仅定义背景色)lv_obj_t *btn = lv_btn_create(screen);lv_obj_set_size(btn,50,30);lv_obj_set_pos(btn,80,50);lv_obj_add_style(btn, &style_default, LV_STATE_DEFAULT);lv_obj_add_style(btn, &style_pressed, LV_STATE_PRESSED);
3、使用 ORed 状态来描述复杂情况的属性。 (例如按下 + 选中 + 聚焦)
效果
:
仅选中:白色(默认状态,无组合状态触发)。
选中 + 按下:绿色(组合状态样式生效)。
static lv_style_t style_default;static lv_style_t style_checked; // 新增:仅选中状态样式 因为后面要手动设置来模拟选中状态,没有这个样式会显示选中状态默认的样式:红色static lv_style_t style_pressed_checked; // 按下 + 选中 组合状态lv_style_init(&style_default);lv_style_set_bg_color(&style_default, lv_color_hex(0xFFFFFF));lv_style_init(&style_checked);lv_style_set_bg_color(&style_checked, lv_color_hex(0xFFFFFF)); // 白色(仅选中,与默认状态统一)lv_style_init(&style_pressed_checked);lv_style_set_bg_color(&style_pressed_checked, lv_color_hex(0x00FF00)); // 绿色(按下且选中)lv_obj_t *btn = lv_btn_create(screen);lv_obj_set_size(btn,50,30);lv_obj_set_pos(btn,80,50);lv_obj_add_style(btn, &style_default, LV_STATE_DEFAULT);// 绑定仅选中状态(未按下)lv_obj_add_style(btn, &style_checked, LV_STATE_CHECKED);// 绑定组合状态:按下(LV_STATE_PRESSED)+ 选中(LV_STATE_CHECKED)lv_obj_add_style(btn, &style_pressed_checked, LV_STATE_PRESSED | LV_STATE_CHECKED);// 手动设置按钮为选中状态(模拟场景)lv_obj_add_state(btn, LV_STATE_CHECKED);
4、为不同的状态使用不同的样式元素可能是个好主意。 例如,为released、pressed、checked+pressed、focused、focused+pressed、focused+pressed+checked等状态寻找背景颜色是相当困难的。 相反,例如,对按下和选中状态使用背景颜色,并使用不同的边框颜色指示聚焦状态。
Inheritance(继承)
某些属性(通常与文本相关)可以从父对象的样式继承。 仅当未在对象的样式中设置给定属性时(即使在默认状态下),才应用继承。 在这种情况下,如果该属性是可继承的,则该属性的值也将在父项中搜索,直到一个对象为该属性指定了一个值。父母将使用自己的状态来确定该值。 因此,如果按下按钮,并且文本颜色来自此处,则将使用按下的文本颜色。
Parts
LVGL 中存在以下预定义部分:
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
可以从这里添加自定义部件。
滑条
// 定义三个部分的样式(背景、指标、旋钮)
static lv_style_t style_bg; // 滑块背景样式
static lv_style_t style_indic; // 滑块指标样式(已选中部分)
static lv_style_t style_knob; // 滑块旋钮样式/* 1. 初始化样式 */
// 背景样式(未选中部分)
lv_style_init(&style_bg);
lv_style_set_bg_color(&style_bg, lv_color_hex(0xEEEEEE)); // 浅灰色背景
lv_style_set_bg_opa(&style_bg, LV_OPA_100); // 不透明
lv_style_set_radius(&style_bg, 10); // 圆角10px
lv_style_set_pad_ver(&style_bg, 5); // 上下内边距5px(控制高度)// 指标样式(已选中部分)
lv_style_init(&style_indic);
lv_style_set_bg_color(&style_indic, lv_color_hex(0x007BFF)); // 蓝色指标
lv_style_set_bg_opa(&style_indic, LV_OPA_100);
lv_style_set_radius(&style_indic, 10); // 与背景圆角一致
lv_style_set_pad_ver(&style_indic, 5); // 与背景高度匹配// 旋钮样式(拖动的圆形按钮)
lv_style_init(&style_knob);
lv_style_set_bg_color(&style_knob, lv_color_hex(0xFFFFFF)); // 白色旋钮
lv_style_set_border_color(&style_knob, lv_color_hex(0x007BFF)); // 蓝色边框
lv_style_set_border_width(&style_knob, 2); // 边框宽度2px
lv_style_set_radius(&style_knob, LV_RADIUS_CIRCLE); // 圆形旋钮
lv_style_set_width(&style_knob, 20); // 旋钮大小20x20px
lv_style_set_height(&style_knob, 20); /* 2. 创建滑块对象 */
lv_obj_t *slider = lv_slider_create(lv_scr_act()); // 在当前屏幕创建滑块
lv_obj_set_size(slider, 200, LV_SIZE_CONTENT); // 宽度200px,高度自适应
lv_obj_center(slider); // 居中显示/* 3. 为滑块的不同部分绑定样式 */
// 背景部分(LV_PART_MAIN 对应滑块整体背景)
lv_obj_add_style(slider, &style_bg, LV_PART_MAIN | LV_STATE_DEFAULT);
// 指标部分(LV_PART_INDICATOR 对应已选中的进度条)
lv_obj_add_style(slider, &style_indic, LV_PART_INDICATOR | LV_STATE_DEFAULT);
// 旋钮部分(LV_PART_KNOB 对应可拖动的按钮)
lv_obj_add_style(slider, &style_knob, LV_PART_KNOB | LV_STATE_DEFAULT);/* 4. 可选:添加滑块值显示标签 */
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Value: 0");
lv_obj_align_to(label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); // 显示在滑块下方// 2. 绑定事件时传递回调函数和用户数据
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, label);