LVGL学习笔记

1.对象

屏幕

屏幕是没有父类的基础对象

LVGL的三层屏幕:

  1. lv_scr_act(void); // 活动屏幕 disp->act_scr

  2. lv_layer_top (void); // 顶层 disp->top_layer

  3. lv_layer_sys (void); // 系统层 disp->sys_layer

设置相对于父级的位置(Position)

1
2
3
4
5
6
设置x轴方向的坐标位置:
lv_obj_set_x(obj, new_x);
设置y轴方向的坐标位置:
lv_obj_set_y(obj, new_y);
同时设置x、y坐标位置:
lv_obj_set_pos(obj, new_x, new_y); //position

对齐(Alignment)

1
2
3
4
5
6
7
8
参照父对象对齐:
lv_obj_set_align(obj, LV_ALIGN_...);
参照父对象对齐后再设置坐标位置:
lv_obj_align(obj, LV_ALIGN_..., x, y);
参照另一个对象(无父子关系)对齐后设置坐标位置:
lv_obj_align_to(obj_to_align, obj_referece, LV_ALIGN_..., x, y)
让图片下方的文本参照图片对齐:
lv_obj_align_to(text, image, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);

对齐类型(LV_ALIGN_…)

1

获取位置(Get position)

1
2
3
4
获取x轴坐标位置:
lv_obj_get_x(obj);
获取y轴坐标位置:
lv_obj_get_y(obj);

父子关系

1
2
3
4
5
6
7
8
9
10
11
为对象设置新的父级
lv_obj_set_parent(obj, new_parent);
获取当前父级
lv_obj_get_parent(obj);
获取父母的特定孩子
lv_obj_get_child(parent, idx);
0 获取创建的第一个子项
1 获取创建的第二个子项
-1 获取最后创建的子项
返回对象在其父对象中的索引
lv_obj_get_index(obj);

LVGL对象的盒子模型

2

LVGL 遵循 CSS 的 border-box 模型。 对象的“盒子”由以下部分构成:
边界(bounding):元素的宽度/高度围起来的区域(整个盒子)。
边框(border):边框有大小和颜色等属性(相当于盒子的厚度和它的颜色)。
填充(padding):对象两侧与其子对象之间的空间(盒子的填充物)。
内容(content):如果边界框按边框宽度和填充的大小缩小,则显示其大小的内容区域(盒子实际装东西的区域)。
轮廓(outline) :LVGL中没有外边距(margin)的概念(盒子之间的距离),确认代之的是轮廓(outline)。它是绘制于元素(盒子)周围的一条线,它不占据空间,位于边框边缘的外围,可起到突出元素(盒子)的作用。在浏览器里,当鼠标点击或使用Tab键让一个选项或者一个图片获得焦点的时候,这个元素就会多了一个轮廓框围绕。轮廓(outline) 。
LVGL的盒子模型是我们理解对象(部件)的组成,修改对象的样式,实现对对象的布局、处理对象排列等等的关键。

样式总结

Styles 用于设置对象的外观

样式是 lv_style_t 变量,它可以保存边框宽度、文本颜色等属性

将样式(变量)分配给对象就可以改变其外观。

在赋值过程中,可以指定目标部分和目标状态。

一个样式可以给多个对象使用(正常样式)。

样式可以级联,也就是可以将多个样式分配给一个对象。

LVGL 会优先使用我们定义的样式,如果没有就会使用默认值。

后来添加的样式具有更高的优先级。

如果对象中未指定某些属性(例如文本颜色),就会从父级继承。

上面说的是 “正常” 样式,对象还有本地样式,它比 “正常” 样式具有更高的优先级。

默认有一个样式主题,我们也可以自己定义样式主题,作为默认的样式主题使用。

初始化样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
static void lv_example_slider_2(void)
{
/*Create a transition*/
static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, 0};
static lv_style_transition_dsc_t transition_dsc;
lv_style_transition_dsc_init(&transition_dsc, props, lv_anim_path_linear, 300, 0, NULL);

static lv_style_t style_main; // 矩形背景部分
static lv_style_t style_indicator; // 指针部分
static lv_style_t style_knob; // 旋钮部分
static lv_style_t style_pressed_color; // 对象某部分被按下时,该部分样式应用的颜色

// 矩形背景部分
lv_style_init(&style_main);
lv_style_set_bg_opa(&style_main, LV_OPA_COVER);
lv_style_set_bg_color(&style_main, lv_palette_main(LV_PALETTE_PINK));
//lv_style_set_outline_width(&style_main, 5);
//lv_style_set_border_width(&style_main, 2);
lv_style_set_radius(&style_main, LV_RADIUS_CIRCLE);
lv_style_set_pad_ver(&style_main, -2); /*Makes the indicator larger*/

// 指针部分
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_LIGHT_BLUE));
lv_style_set_radius(&style_indicator, LV_RADIUS_CIRCLE);
lv_style_set_transition(&style_indicator, &transition_dsc);

// 旋钮部分
lv_style_init(&style_knob);
lv_style_set_bg_opa(&style_knob, LV_OPA_COVER);
lv_style_set_bg_color(&style_knob, lv_palette_main(LV_PALETTE_CYAN));
lv_style_set_border_color(&style_knob, lv_palette_darken(LV_PALETTE_CYAN, 3));
lv_style_set_border_width(&style_knob, 2);
lv_style_set_radius(&style_knob, LV_RADIUS_CIRCLE);
lv_style_set_pad_all(&style_knob, 8); /*Makes the knob larger*/
lv_style_set_transition(&style_knob, &transition_dsc);

// 对象某部分被按下时,该部分样式应用的颜色
lv_style_init(&style_pressed_color);
lv_style_set_bg_color(&style_pressed_color, lv_palette_darken(LV_PALETTE_BLUE, 2));

/*Create a slider and add the style*/
lv_obj_t * slider = lv_slider_create(lv_scr_act());

//lv_obj_remove_style_all(slider); // 删除对象的所有样式
//lv_obj_remove_style(obj, &style_obj, selector); // 删除对象特定样式

lv_obj_add_style(slider, &style_main, LV_PART_MAIN); // 矩形背景部分
lv_obj_add_style(slider, &style_indicator, LV_PART_INDICATOR); // 指针部分
lv_obj_add_style(slider, &style_pressed_color, LV_PART_INDICATOR | LV_STATE_FOCUSED); // 当指针部分被按下的时候,指针部分应用该样式
lv_obj_add_style(slider, &style_knob, LV_PART_KNOB); // 旋钮部分,像按钮一样可以抓取调整值
lv_obj_add_style(slider, &style_pressed_color, LV_PART_KNOB | LV_STATE_FOCUSED); // 当旋钮部分被按下的时候,旋钮部分应用该样式

lv_obj_center(slider);
}

void lv_100ask_demo_course_2_2_5(void)
{
#if 1
/**
样式存储在lv_style_t变量中。样式变量应该是静态、全局或动态分配的。
也就是它们不能是函数中的局部变量,因为当函数结束时它们会被销毁。
样式初始化示例:
*/
static lv_style_t style_obj;
lv_style_init(&style_obj);

/**
设置样式属性:
lv_style_set_<property_name>(&style, <value>);
*/
lv_style_set_bg_color(&style_obj, lv_palette_main(LV_PALETTE_DEEP_ORANGE)); // 设置背景色
lv_style_set_text_color(&style_obj, lv_palette_main(LV_PALETTE_DEEP_ORANGE)); // 设置文字颜色
lv_style_set_bg_opa(&style_obj, LV_OPA_COVER); // 设置透明度

// 创建对象
lv_obj_t * obj = lv_obj_create(lv_scr_act());
lv_obj_t * obj2 = lv_obj_create(lv_scr_act());
lv_obj_align(obj2, LV_ALIGN_CENTER, 0 ,0);

// 本地样式
lv_obj_set_style_bg_color(obj, lv_palette_main(LV_PALETTE_YELLOW), LV_STATE_PRESSED); // 设置背景色
lv_obj_set_style_bg_color(obj2, lv_palette_main(LV_PALETTE_AMBER), LV_STATE_PRESSED); // 设置背景色
lv_obj_set_style_bg_opa(obj, LV_OPA_50, LV_STATE_PRESSED); // 设置背景透明度

/**
添加样式到对象:
lv_obj_add_style(obj, &style, <selector>)
参数“obj”就是要R-ed 值 (不能是互斥,否添加到的对象,
“style”是指向样式变量的指针,
<selector>是应添加样式的部分和状态的,O则就是清除标志,没法合并)。
*/
lv_obj_add_style(obj, &style_obj, 0); // 默认状态: LV_STATE_DEFAULT
lv_obj_add_style(obj2, &style_obj, 0); // 默认状态: LV_STATE_DEFAULT

lv_obj_add_style(obj, &style_obj, LV_STATE_PRESSED); // 按下状态,当对象被按下的时候应用该样式
lv_obj_add_style(obj2, &style_obj, LV_STATE_PRESSED); // 按下状态,当对象被按下的时候应用该样式
#endif

// 滑杆示例(不需要深入研究,体会部件样式的部分和状态即可),看里面的注释:体验流程
//lv_example_slider_2();
}

获取样式属性

1
2
3
4
获取属性的最终值(考虑级联、继承、本地样式和转换):
lv_obj_get_style_<property_name>(obj, <part>);
函数使用对象的当前状态,如果没有更好的候选对象,则返回默认值。 例如
lv_color_t color=lv_obj_get_style_bg_color(obj,LV_PART_MAIN);

删除样式

1
2
3
4
5
6
7
8
9
删除对象的所有样式: lv_obj_remove_style_all(obj);
删除对象的特定样式: lv_obj_remove_style(obj, &style_obj, selector);

只有当 selector 与 lv_obj_add_style 中使用的 selector 匹配时,此函数才会删除 style

如果 style 是空,那么会根据给出的 selector 检查并删除所有匹配的样式如果 selector 是 LV_STATE_ANY 或 LV_PART_ANY 就会删除具有任何状态或部分的样式。

下面这个效果和lv_obj_remove_style_all 的效果是一样的:
lv_obj_remove_style(obj, NULL, LV_STATE_ANY | LV_PART_ANY );

背景部分的属性

1
2
3
4
5
6
7
8
背景属性和我们前面学习的盒子模型关系很大,背景属性主要有一下这些:
背景(Background)
边界(Border)
轮廓(Outline)
阴影(Shadow)
填充(Padding)
宽度和高度变换
X和Y变换

样式的状态和部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
对象可以处于以下状态的组合:
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) 自定义状态
这些可能会随着lvgl的更新而不断增加,同学们可以阅读最新版本的文档获取最新资料。
1
2
3
4
5
6
7
8
9
10
11
对象可以有 部分(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 可以从这里添加自定义部件。
这些可能会随着lvgl的更新而不断增加,同学们可以阅读最新版本的文档获取最新资料。

本地样式

1
2
3
4
5
6
7
8
9
除了“普通” 样式外,对象还可以存储 本地样式(私有样式) 。
本地样式与普通样式类似,但是它不能在其他对象之间共享。如果使用本地样式,将自动分配局部样式,并在删除对象时释放。本地样式对于向对象添加本地自定义很有用。
本地样式的接口函数是这样的格式:
lv_obj_set_style_<property_name>(obj, <value>, <selector>);
示例:
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffffff), 0); // 设置背景色lv_obj_set_style_bg_opa(obj, LV_OPA_50, 0); // 设置背景透明度lv_style_set_style_....
删除本地样式的时候我们删除某一个样式:
lv_obj_remove_local_style_prop(obj, LV_STYLE_..., selector);
LV_STYLE_...的取值请看: lvgl/src/misc/lv_style.h 中的 lv_style_prop_t

样式继承

1
2
某些属性(通常与文本相关)可以从父对象的样式继承。 
只有没有在为对象设置样式属性的时候,才应用继承。 在这种情况下,如果这个属性是可继承的,那这个属性的值会在父类中检索,直到一个对象为该属性指定了一个值。父类将使用自己的状态来确定该值。 因此,如果按下按钮,并且文本颜色来自此处,则将使用按下的文本颜色。

过渡特效

1
2
3
4
默认情况下,当一个对象改变状态(例如它被按下)时,新状态的新属性会立即设置。但是,通过转换,可以在状态更改时播放动画。 例如,按下按钮时,其背景颜色可以在 300 毫秒内动画显示为按下的颜色。
demo体验:
https://docs.lvgl.io/8.1/overview/style.html#transition http://lvgl.100ask.net/8.1/overview/style.html#transition
这部分我们在后面课程再展开讨论

样式主题

1
2
3
4
主题是风格的集合。如果存在活动主题,LVGL将其应用于每个创建的部件(对象)。 这将为UI提供一个默认外观,然后可以通过添加更多样式对其进行修改。
demo体验:
https://docs.lvgl.io/8.1/overview/style.html#extending-the-current-theme http://lvgl.100ask.net/8.1/overview/style.html#extending-the-current-theme
这部分后面的课程再展开讨论。

宏开关

详见官方文档

1
lv_obj_add/clear_flag(obj, LV_OBJ_FLAG_...); 启用/禁用

事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

#if 0
static void my_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e); // 获取触发事件的部件(对象)
lv_event_code_t code = lv_event_get_code(e); // 获取当前部件(对象)触发的事件代码
lv_obj_t * label = lv_event_get_user_data(e); // 获取添加事件时传递的用户数据
static int count = 0;
switch(code){
case LV_EVENT_PRESSED:
lv_label_set_text(label, "LV_EVENT_PRESSED");
lv_obj_set_style_bg_color(obj, lv_color_hex(0xc43e1c), 0); // 通过本地样式(私有样式)设置背景色
printf("LV_EVENT_PRESSED\n");
break;
case LV_EVENT_LONG_PRESSED:
lv_label_set_text(label, "LV_EVENT_LONG_PRESSED");
lv_obj_set_style_bg_color(obj, lv_color_hex(0x4cbe37), 0); // 通过本地样式(私有样式)设置背景色
printf("LV_EVENT_LONG_PRESSED\n");
break;
default:
//lv_label_set_text(label,"Bsgbsg7");
//lv_obj_set_style_bg_color(obj, lv_color_hex(0xcc33ff), 0);
//printf("default\n");
break;
}
}

void lv_100ask_demo_course_2_2_6(void)
{
/* 创建基础部件(对象) */
lv_obj_t * obj = lv_obj_create(lv_scr_act());

/* 创建label部件(对象) */
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Bsgbsg7"); // 设置label展示的文字
lv_obj_center(label); // 将对象与其父对象的中心对齐,这里的父对象是屏幕:lv_scr_act()

// 为obj1添加事件回调函数,所有的事件类型都能触发该回调函数
lv_obj_add_event_cb(obj, my_event_cb, LV_EVENT_ALL, label);
}
#endif // 0



/* 事件冒泡 */
#if 1
static void my_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e); // 获取触发事件的对象
lv_obj_t * parent = lv_event_get_current_target(e); // 获取触发事件对象的父对象(事件冒泡才有)
/*
注意此处的parent获取到了最外层的,即obj1
*/
lv_event_code_t code = lv_event_get_code(e); // 获取当前部件触发的事件代码
lv_obj_t * label = lv_event_get_user_data(e); // 获取添加事件时传递的用户数据

switch(code){
case LV_EVENT_PRESSED:
lv_label_set_text(label, "LV_EVENT_PRESSED");
lv_obj_align_to(label, obj, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_bg_color(parent, lv_color_hex(0xc43e1c), 0); // 通过本地样式(私有样式)设置背景色
lv_obj_set_style_bg_color(obj, lv_color_hex(0xc43e1c), 0); // 通过本地样式(私有样式)设置背景色
printf("LV_EVENT_PRESSED\n");
break;
case LV_EVENT_CLICKED:
lv_obj_remove_local_style_prop(parent, LV_STYLE_BG_COLOR, 0); // 删除通过本地样式(私有样式)设置的背景色
lv_obj_remove_local_style_prop(obj, LV_STYLE_BG_COLOR, 0); // 删除通过本地样式(私有样式)设置的背景色
lv_label_set_text(label, "Bsgbsg7");
lv_obj_align_to(label, obj, LV_ALIGN_CENTER, 0, 0);
printf("LV_EVENT_CLICKED\n");
break;
default:
//printf("NONE\n");
break;
}
}

void lv_100ask_demo_course_2_2_6(void)
{
/* 创建一个基础对象 obj1 */
lv_obj_t * obj1 = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj1, 450, 250);
lv_obj_center(obj1); // 将对象与其父对象的中心对齐,这里的父对象是屏幕:lv_scr_act()

/* 以 obj1 创建一个基础对象 obj2 */
lv_obj_t * obj2 = lv_obj_create(obj1);
lv_obj_set_size(obj2, 400, 200);
lv_obj_center(obj2); // 将对象与其父对象的中心对齐,这里的父对象是屏幕:obj1
lv_obj_add_flag(obj2, LV_OBJ_FLAG_EVENT_BUBBLE); // 启用事件冒泡,将接收到的所有事件传播给父级

/* 以 obj2 创建一个基础对象 obj3 */
lv_obj_t * obj3 = lv_obj_create(obj2);
lv_obj_set_size(obj3, 350, 150);
lv_obj_center(obj3); // 将对象与其父对象的中心对齐,这里的父对象是屏幕:obj2
lv_obj_add_flag(obj3, LV_OBJ_FLAG_EVENT_BUBBLE); // 启用事件冒泡,将接收到的所有事件传播给父级

/* 以 obj3 创建一个基础对象 obj4 */
lv_obj_t * obj4 = lv_obj_create(obj3);
lv_obj_set_size(obj4, 300, 100);
lv_obj_center(obj4); // 将对象与其父对象的中心对齐,这里的父对象是屏幕:obj3
lv_obj_add_flag(obj4, LV_OBJ_FLAG_EVENT_BUBBLE); // 启用事件冒泡,将接收到的所有事件传播给父级

/* 以屏幕为父类,创建一个label部件(对象) */
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Bsgbsg7"); // 设置label展示的文字
lv_obj_align_to(label, obj1, LV_ALIGN_CENTER, 0, 0); // 将label相对于obj1对齐

//将给obj1添加事件回调函数,所有的事件类型都能触发该回调函数
lv_obj_add_event_cb(obj1, my_event_cb, LV_EVENT_ALL, label);
/*
注意此处应该理解为obj2,3,4被触发之后,会将事件传给父类,直到传到能够处理此事件的父类(即lv_obj_add_event_cb内部的obj)
如果是obj2,则都会传给obj2处理,obj1无法处理
*/
}
#endif // 1
#endif

添加事件

1
lv_obj_add_event_cb(obj, event_cb, event_code, user_data);

发送事件

1
lv_event_send(obj, event_cb, event_code, user_data);

删除事件

1
2
3
lv_obj_remove_event_cb(obj, event_cb);
lv_obj_remove_event_dsc(obj, event_dsc);
//event_dsc 是 lv_obj_add_event_cb 返回的指针

事件类型(event_code)

1
2
3
4
5
6
7
8
9
10
11
12
输入设备事件(Input device events)
绘图事件(Drawing events)
其他事件(Special events)
特殊事件(Other events)
自定义事件(Custom events)

更全面的信息请查阅:
源码:lvgl/src/core/lv_event.h (lv_event_code_t)
开发文档:
英文:https://docs.lvgl.io/8.1/overview/event.html#event-codes
中文:http://lvgl.100ask.net/8.1/overview/event.html#event-codes

事件回调函数的 lv_event_t 参数

1
2
3
4
5
6
7
8
9
10
11
事件回调函数只有一个参数,这个参数对我们的作为非常大,现在的版本提供这些功能:
static void my_event_cb(lv_event_t * event);
获取触发的事件代码:
lv_event_code_t code = lv_event_get_code(e);
获取触发事件的对象:
lv_obj_t * target = lv_event_get_target(e);
获取最初触发事件的对象(事件冒泡):
lv_obj_t * target = lv_event_get_current_target(e);
获取事件传递的用户数据:
lv_event_get_user_data(e); 获取使用 lv_obj_add_event_cb 传递的用户数据
lv_event_get_param(e); 获取使用 lv_event_send 传递的用户数据
1
2
3
4
5
6
一个事件回调函数可给多个对象使用
一个对象可以使用多个事件回调函数

如果传入的用户数据不一样,一个对象可以绑定同一个事件回调函数多次,事件将按照添加的顺序调用。例如:
lv_obj_add_event_cb(obj, my_clicked_event_cb, LV_EVENT_CLICKED, &num1);
lv_obj_add_event_cb(obj, my_clicked_event_cb, LV_EVENT_CLICKED, &num2);

事件冒泡

1
2
3
4
启用方式:
lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE),该对象的所有事件将会发送到该对象的父级,依此类推。
lv_event_get_target(e); 获取触发事件的当前对象。
lv_event_get_current_target(e); 获取事件冒泡的父对象。

标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include "../../lv_100ask_teach_demos.h"
#if LV_USE_100ASK_DEMO_COURSE_3_1_1
#include "lv_100ask_demo_course_3_1_1.h"
//extern lv_font_t bsg;
static void label_event_cb(lv_event_t * e)
{
lv_obj_t * label = lv_event_get_target(e); // 获取触发事件的部件(对象)
lv_event_code_t code = lv_event_get_code(e); // 获取当前部件(对象)触发的事件代码
lv_obj_set_style_bg_opa(label, 100,0);
switch(code){
case LV_EVENT_PRESSED:
lv_label_set_text(label, "LV_EVENT_PRESSED");
lv_obj_set_style_bg_color(label, lv_color_hex(0xc43e1c), 0); // 通过本地样式(私有样式)设置背景色
//printf("LV_EVENT_PRESSED\n");
break;
case LV_EVENT_LONG_PRESSED:
lv_label_set_text(label, "LV_EVENT_LONG_PRESSED");
lv_obj_set_style_bg_color(label, lv_color_hex(0x4cbe37), 0); // 通过本地样式(私有样式)设置背景色
//printf("LV_EVENT_LONG_PRESSED\n");
break;
default:
//printf("NONE\n");
break;
}
}

void lv_100ask_demo_course_3_1_1(void)
{
LV_FONT_DECLARE(bsg);
char * text = "Wecome to Bsgbsg7's LVGL"; // 要显示的文字
// 创建一个label部件(对象),他的父对象是活动屏幕对象
lv_obj_t * label = lv_label_create(lv_scr_act());
//lv_obj_set_size(label,500,50);
lv_obj_center(label);

/* 函数中会另外开辟和给定的字符串大小的空间存放字符串(常用) */
lv_label_set_text(label, text);
//lv_label_set_text(label, "Wecome to Bsgbsg7's LVGL");

/* 也会另外开辟空间存放字符串,但是可以像printf格式化字符串 */
//lv_label_set_text_fmt(label, "%s: %d",text, 30);

/* 直接使用给定的缓冲区(不常用) */
//lv_label_set_text_static(label, text);
//lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR ) ;

/*
设置文本颜色:
lv_style_set_text_color(&style_obj, lv_color_hex(0xf7b37b));
lv_obj_set_style_text_color(label, lv_color_hex(0xf7b37b), 0);
*/
//lv_style_set_text_color(&style_obj, lv_color_hex(0xf7b37b));
//lv_obj_set_style_text_color(label, lv_color_hex(0xf7b37b),0);
//lv_obj_set_style_bg_color(label, lv_color_hex(0xf5b37b),0);
//lv_obj_set_style_bg_opa(label, 100,0);

//lv_label_set_recolor(label, true);
//lv_label_set_text(label, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label");


/*
文本选择:
lv_label_set_text_sel_start(label, 1);
lv_label_set_text_sel_end(label, 6);
*/



/* 设置文字字号(内置ASCII字库) */
/* 使用其他字号的字体,如果不设置默认使用 lv_font_montserrat_14 ,在 lv_conf.h 中 LV_FONT_DEFAULT 定义 */
lv_obj_set_style_text_font(label, &bsg, 0);
lv_label_set_text(label, "山东大学(青岛)");

//lv_label_set_text(label, LV_SYMBOL_OK LV_SYMBOL_WIFI LV_SYMBOL_PLAY); // 多个图标一起使用

/* 让 label 可以响应输入事件 */
//lv_obj_add_flag(label, LV_OBJ_FLAG_CLICKABLE);
//lv_obj_add_event_cb(label, label_event_cb, LV_EVENT_ALL, 0);
}


#endif /* LV_USE_100ASK_DEMO_COURSE_3_1_1 */

在盒子模型里面,标签的组成包括:

1
2
3
4
LV_PART_MAIN 矩形部分(盒子区域)。 填充值可用于在文本和背景之间添加空间。
LV_PART_SCROLLBAR 当要展示的文本大于部件的大小时,显示的滚动条部分。
LV_PART_SELECTED 选中文本时,突出显示的部分。
label只能使用 text_color 和 bg_color 样式属性。

创建标签:

1
lv_obj_t * label = lv_label_create(parent);

设置显示文本

1
2
3
4
5
6
7
8
9
10
11
直接设置要显示的文本:
lv_label_set_text(label, "New text");

格式化给定要显示的文本:
lv_label_set_text_fmt(label, “%s: %d”, “Value”, 15);

文本不存储在动态内存中,而是直接使用给定的缓冲区:
lv_label_set_text_static(label, "New text");

要在label换行非常简单,像printf函数那样使用 \n 即可:
lv_label_set_text(label, " line1\nline2\n\nline4 ");

大小

1
lv_label_set_long_mode(label, LV_LABEL_LONG_...) 指定模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
默认情况标签的大小会自动拓展成和文本一样的大小(LV_SIZE_CONTENT)
lv_obj_set_size lv_obj_set_width lv_obj_set_height

下面是几种模式:
LV_LABEL_LONG_WRAP 、
如果有多个换行,并且如果高度为LV_SIZE_CONTENT,那么高度会根据文本换行被自动扩展;否则文本将被剪掉。(默认设置)

LV_LABEL_LONG_DOT
如果文本太长,就保持大小并在末尾写3个点 .

LV_LABEL_LONG_SCROLL
如果文本比标签宽(太长),则可以水平来回滚动显示它。如果它很高(多个\n换行),可以垂直滚动。只滚动一个方向,水平滚动的优先级更高。

LV_LABEL_LONG_SCROLL_CIRCULAR
如果文本比标签宽,则水平滚动它。如果它更高,就垂直滚动。只滚动一个方向,水平滚动的优先级更高。

LV_LABEL_LONG_CLIP
剪掉超出标签范围外的文本部分。

注意:LV_LABEL_LONG_DOT 是直接操作文本缓冲区以添加/删除点。如果使用 lv_label_set_text 和 lv_label_set_text_fmt 它们会分配一个单独的缓冲区,不会出问题。但是如果使用 lv_label_set_text_static 时我们传递给它的缓冲区必须是可写的。

文本着色

1
2
lv_style_set_text_color(&style_obj, lv_color_hex(0xf7b37b));
lv_obj_set_style_text_color(label, lv_color_hex(0xf7b37b), 0);

也可以让文本某些部分重新着色,例如:

1
2
3
4
lv_label_set_recolor(label1, true);
lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label);


文本选择

1
2
3
4
如果在 lv_conf.h 中打开了 LV_LABEL_TEXT_SELECTION (默认开启),就可以选择部分文本了。这个和我们在PC用鼠标选中文本类似,但是这个效果只能在文本框(lv_textarea)中实现。Label只能事先手动选择指定范围的文本:
lv_label_set_text_sel_start(label, 1);
lv_label_set_text_sel_end(label, 6);
注意,这里的第一个字符从1开始算,而不是0。

显示图标

image-20221223001642589

用法(LV_SYMBOL_…):

1
2
3
lv_label_set_text(my_label, LV_SYMBOL_OK); // 直接显示图标
lv_label_set_text(my_label, LV_SYMBOL_OK “Apply”); // 图标与字符串一起使用
lv_label_set_text(my_label, LV_SYMBOL_OK LV_SYMBOL_WIFI LV_SYMBOL_PLAY); // 多个图标一起使用

事件处理

1
2
Label默认不接收输入事件,如果我们想设置输入类型的样式或者事件会无法生效,就需要打开 LV_OBJ_FLAG_CLICKABLE,示例:
lv_obj_add_flag(label, LV_OBJ_FLAG_CLICKABLE); // 使输入设备可点击对象

显示中文

1
2
3
4
5
6
7
8
9
LVGL内置有一个中文字库 [CJK](https://zh.wikipedia.org/wiki/中日韓統一表意文字)[字库](https://zh.wikipedia.org/wiki/中日韓統一表意文字) ,这个字库在 lv_conf.h中定义为:LV_FONT_SIMSUN_16_CJK。

要在lvgl中使用显示自己的中文字库,我们需要用到两个东西:字体文件和字体转换器。

字体文件我们可以使用开源的字体或者自己制作出来,准备好了字体文件之后使用字体转换器即可转换成可以在lvgl上使用的字体格式。开源字体获取页面:
http://lvgl.100ask.net/8.1/tools/fonts-zh-source.html

准备好字体文件之后就可以通过lvgl官方提供的字体转换器,提取转换你想要的字体,LVGL官方在线字体转换器页面:
[ https://lvgl.io/tools/fontconverter](https://lvgl.io/tools/fontconverter)
1
2
3
4
5
6
7
1.为要输出字体命名。例如“font_source_han_sans_bold_20”
2.以 px为单位指定高度(字体大小)
3.设置bpp (bit-per-piel)。值越高,字体越平滑(抗锯齿)
4.选择TTF 或 WOFF 格式字体文件
5.设置要包含在字体中的 Unicode 字符范围或在符号字段中列出字符
6.可以同时选择多个字体文件转换,并为其指定范围和/或符号。这些字符将被合并转换到同一个文件中。
7.单击转换按钮以下载转换出来的 font_source_han_sans_bold_20.c 文件。

image-20221223001716190

1
2
3
4
5
6
7
8
9
10
1.将结果 C 文件复制到你的 LVGL 项目中,并包含到项目;
2.在你的项目应用程序的 C 文件中,将字体声明为:
extern lv_font_t my_font_name;
或:
LV_FONT_DECLARE(my_font_name);
3.在样式中设置字体:
lv_style_set_text_font(&style_obj, &my_font_name); // 普通(共享)样式
lv_obj_set_style_text_font(label, &my_font_name, 0); // 私有(本地)样式
4.unicode 是统一所有语言的一套编码。
5.utf-8是基于unicode编码的一种节约字节的编码。

按钮