目录
简介
基础对象的作用
作为背景装饰
lv_obj_t * obj = lv_obj_create(lv_scr_act());
辅助布局
当 GUI 界面中有一些组成内容相似的模块时,可以利用基础对象作为父对象,创建出其他的部件,这些部件将出现在基础对象内部,此时,我们只需要管理各基础对象之间的布局即可,其他的部件会随之变化。辅助布局的示意图如下:
lv_obj_t * obj1 = lv_obj_create(lv_scr_act());
lv_obj_t * obj2 = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj1,200,200);
lv_obj_set_size(obj2,200,200);
lv_obj_align_to(obj1,obj2,LV_ALIGN_OUT_RIGHT_MID,0,0);
lv_obj_t * obj3 = lv_obj_create(obj1);
lv_obj_t * obj4 = lv_obj_create(obj2);
界面切换
当基础对象做为父对象,创建出其他的部件时,这些被创建出来的部件将出现在其父对象的内部,换言之,此时的基础对象就是一个容器,它里面子对象会随之移动。在 UI 设计中,我们可以利用上述的特性,实现界面的切换,示意图如下所示:
由上图可知,基础对象 1、2 分别用于管理界面 1、2,它们之中存在一些子对象(例如开关),当用户需要切换界面时,只需切换容器即可。这一点非常的重要,尤其是在我们做LVGL项目的时候,往往需要通过这种方法实现不同界面的且切换。
当用户删除一个父对象时,它所有的子对象也会被一并删除,因此,我们需要实现界面的切换,可以调用 lv_obj_del 函数,直接删除基础对象(父对象),然后再创建新的界面,这样即可实现界面切换,示意图如下所示:
此方法的原理和删除法类似,只不过这里是将界面隐藏起来,需要的时候还能还原。注意:隐藏的界面并未被删除,其占用内存也没有得到释放,因此,当用户使用此方法切换界面时,需要考虑内存溢出的隐患。隐蔽法的示意图如下所示:
由上图可知,隐藏法的实现逻辑如下:先创建出不同的界面,然后调用 lv_obj_add_flag 函数,为指定的界面添加隐藏的标志,此时,该界面将隐藏,而当我们需要显示某个界面时,只需要调用 lv_obj_clear_flag 函数,清除隐藏属性即可。注意:不要同时清除多个界面的隐藏属性,否则可能出现显示混乱的问题。下面我们来看一下上述的两个函数:
1.lv_obj_add_flag 函数
设置一个或多个标志,其函数原型如下所示:
void lv_obj_add_flag(lv_obj_t *obj, lv_obj_flag_t f);
返回值:无。
2. lv_obj_clear_flag 函数
void lv_obj_clear_flag(lv_obj_t *obj, lv_obj_flag_t f);
返回值:无。
在 LVGL 中,标志相关的枚举如下源码所示:
enum {LV_OBJ_FLAG_HIDDEN = ( 1L << 0 ), /* 隐藏 */LV_OBJ_FLAG_CLICKABLE = ( 1L << 1 ),LV_OBJ_FLAG_CLICK_FOCUSABLE = ( 1L << 2 ),LV_OBJ_FLAG_CHECKABLE = ( 1L << 3 ),LV_OBJ_FLAG_SCROLLABLE = ( 1L << 4 ),LV_OBJ_FLAG_SCROLL_ELASTIC = ( 1L << 5 ),LV_OBJ_FLAG_SCROLL_MOMENTUM = ( 1L << 6 ),LV_OBJ_FLAG_SCROLL_ONE = ( 1L << 7 ),LV_OBJ_FLAG_SCROLL_CHAIN_HOR = ( 1L << 8 ),LV_OBJ_FLAG_SCROLL_CHAIN_VER = ( 1L << 9 ),LV_OBJ_FLAG_SCROLL_CHAIN = ( LV_OBJ_FLAG_SCROLL_CHAIN_HOR |LV_OBJ_FLAG_SCROLL_CHAIN_VER ),LV_OBJ_FLAG_SCROLL_ON_FOCUS = ( 1L << 10 ),LV_OBJ_FLAG_SCROLL_WITH_ARROW = ( 1L << 11 ),LV_OBJ_FLAG_SNAPPABLE = ( 1L << 12 ),LV_OBJ_FLAG_PRESS_LOCK = ( 1L << 13 ),LV_OBJ_FLAG_EVENT_BUBBLE = ( 1L << 14 ),LV_OBJ_FLAG_GESTURE_BUBBLE = ( 1L << 15 ),LV_OBJ_FLAG_ADV_HITTEST = ( 1L << 16 ),LV_OBJ_FLAG_IGNORE_LAYOUT = ( 1L << 17 ),LV_OBJ_FLAG_FLOATING = ( 1L << 18 ),LV_OBJ_FLAG_OVERFLOW_VISIBLE = ( 1L << 19 ),LV_OBJ_FLAG_LAYOUT_1 = ( 1L << 23 ),LV_OBJ_FLAG_LAYOUT_2 = ( 1L << 24 ),LV_OBJ_FLAG_WIDGET_1 = ( 1L << 25 ),LV_OBJ_FLAG_WIDGET_2 = ( 1L << 26 ),LV_OBJ_FLAG_USER_1 = ( 1L << 27 ),LV_OBJ_FLAG_USER_2 = ( 1L << 28 ),LV_OBJ_FLAG_USER_3 = ( 1L << 29 ),LV_OBJ_FLAG_USER_4 = ( 1L << 30 ),};
详细解释
每个枚举值是一个位掩码
每个枚举值表示一个特定的属性,其值是 1L 左移一定的位数。
例如,LV_OBJ_FLAG_HIDDEN = (1L << 0) 表示第 0 位的标志位用来指示对象是否“隐藏”。
位掩码的设计允许将多个属性组合在一起存储在一个整数中,通过按位操作进行设置、清除或判断。
属性分类与用途 每个枚举值描述了一个对象的特定属性或行为,例如是否可点击、是否可滚动、是否隐藏等。这些属性可以通过按位或 (|) 运算符进行组合。
属性解释
名称 | 值 | 说明 |
---|---|---|
LV_OBJ_FLAG_HIDDEN | 1L << 0 (0x0001) | 对象是否隐藏。隐藏时不可见但仍存在于布局中。 |
LV_OBJ_FLAG_CLICKABLE | 1L << 1 (0x0002) | 对象是否可以点击。如果设为不可点击,则不会响应点击事件。 |
LV_OBJ_FLAG_CLICK_FOCUSABLE | 1L << 2 (0x0004) | 点击时是否获取焦点。适用于需要切换焦点的交互控件。 |
LV_OBJ_FLAG_CHECKABLE | 1L << 3 (0x0008) | 对象是否可选中,例如按钮或复选框。 |
LV_OBJ_FLAG_SCROLLABLE | 1L << 4 (0x0010) | 对象是否可滚动。适用于滚动容器。 |
LV_OBJ_FLAG_SCROLL_ELASTIC | 1L << 5 (0x0020) | 滚动是否有弹性效果,通常用于提升用户体验。 |
LV_OBJ_FLAG_SCROLL_MOMENTUM | 1L << 6 (0x0040) | 滚动是否具有惯性效果(滑动后继续滚动一段距离)。 |
LV_OBJ_FLAG_SCROLL_ONE | 1L << 7 (0x0080) | 是否只能滚动一个元素(例如单项选择列表)。 |
LV_OBJ_FLAG_SCROLL_CHAIN_HOR | 1L << 8 (0x0100) | 水平滚动是否可以链式滚动(与父对象联动)。 |
LV_OBJ_FLAG_SCROLL_CHAIN_VER | 1L << 9 (0x0200) | 垂直滚动是否可以链式滚动(与父对象联动)。 |
LV_OBJ_FLAG_SCROLL_CHAIN | (1L << 8) | (1L << 9) | 水平和垂直方向都支持链式滚动。 |
LV_OBJ_FLAG_SCROLL_ON_FOCUS | 1L << 10 (0x0400) | 当对象获得焦点时自动滚动到可见区域。 |
LV_OBJ_FLAG_SCROLL_WITH_ARROW | 1L << 11 (0x0800) | 是否可以通过方向键滚动。 |
LV_OBJ_FLAG_SNAPPABLE | 1L << 12 (0x1000) | 对象是否可以对齐到某个位置,例如网格或边界。 |
LV_OBJ_FLAG_PRESS_LOCK | 1L << 13 (0x2000) | 按下对象后,是否锁定对象直到释放按键。 |
LV_OBJ_FLAG_EVENT_BUBBLE | 1L << 14 (0x4000) | 事件是否可以冒泡到父对象,用于事件传播机制。 |
LV_OBJ_FLAG_GESTURE_BUBBLE | 1L << 15 (0x8000) | 手势事件是否可以冒泡到父对象。 |
LV_OBJ_FLAG_ADV_HITTEST | 1L << 16 (0x10000) | 使用高级命中测试,判断点击是否在特定区域内。 |
LV_OBJ_FLAG_IGNORE_LAYOUT | 1L << 17 (0x20000) | 忽略布局管理,允许对象独立定位。 |
LV_OBJ_FLAG_FLOATING | 1L << 18 (0x40000) | 对象是否浮动在布局之上。 |
LV_OBJ_FLAG_OVERFLOW_VISIBLE | 1L << 19 (0x80000) | 内容溢出时是否仍然显示溢出的部分。 |
LV_OBJ_FLAG_LAYOUT_1/2 | 1L << 23/24 | 用于指定布局类型的标志位。 |
LV_OBJ_FLAG_WIDGET_1/2 | 1L << 25/26 | 用于定义某些特定小部件的标志位。 |
LV_OBJ_FLAG_USER_1/2/3/4 | 1L << 27~30 | 用户自定义标志位,供用户根据需求添加自定义功能。 |
基础对象的相关知识
基础对象的大部分知识, 我们在LVGL基础知识(入门必看)中已经介绍过,这里我们只介绍一个拓展的内容:扩大点击区域。
在默认的情况下,用户必须要在区域边界内点击对象,这样才能成功触发事件(例如按下)。如果我们想扩展点击区域,可以调用 lv_obj_set_ext_click_area 函数来设置,其函数原型如下所示:
void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t size)
返回值:无
基础对象的 API 函数
函数名称 | 功能 | 主要参数 | 返回值 |
---|---|---|---|
| 创建一个基础对象(矩形)。 |
| 新创建对象的指针。 |
| 设置对象的用户数据字段 ( |
| 无返回值。 |
| 检查对象是否设置了指定标志。 |
|
|
| 检查对象是否设置了任意一个指定标志(可以是多个的组合)。 |
|
|
| 获取对象的当前状态。 |
| 返回对象的状态,类型为 |
| 检查对象是否处于指定状态。 |
|
|
| 获取对象所属的组,用于输入焦点管理。 |
| 返回对象所属的组指针;若无组,返回 |
| 获取对象的用户数据。 |
| 返回用户数据(之前设置的 |
| 为对象分配特殊属性数据( |
| 无返回值。 |
| 检查对象类型是否匹配某种类型。 |
|
|
| 检查对象是否属于指定类或其派生类。 |
|
|
| 获取对象所属的类信息。 |
| 返回对象所属的类信息指针。 |
| 检查对象是否仍然有效(未被删除)。 |
|
|
基础对象部件的实验
本实验主要测试基础对象 API 函数的使用,实验现象:开机后,屏幕上会显示两个矩形,当长按大矩形时,会改变其位置,小矩形位置也随之改变,当按下小矩形并释放时,小矩形的位置会改变,其超出大矩形的部分将不可见。与此同时,打印对应事件,表面触发了对应事件。
/* 获取当前活动屏幕的宽高 */
#define scr_act_width() lv_obj_get_width(lv_scr_act())
#define scr_act_height() lv_obj_get_height(lv_scr_act())
static lv_coord_t scr_act_width;
static lv_coord_t scr_act_height;
static lv_obj_t *parent_obj;
static lv_obj_t *child_obj;
static void obj_event_cb(lv_event_t *e)
{
lv_obj_t * target = lv_event_get_target(e); /* 获取事件触发源 */
if (target == parent_obj) /* 判断触发源:是不是父对象? */
{
/* 重新设置父对象的位置:居中 */
lv_obj_align(parent_obj, LV_ALIGN_CENTER, 0, 0);
printf("parent_obj\n");
}
else if (target == child_obj) /* 判断触发源:是不是子对象? */
{
/* 重新设置子对象的位置:右侧居中,再向 X 轴偏移 100 */
lv_obj_align(child_obj, LV_ALIGN_RIGHT_MID, 100, 0);
printf("child_obj\n");
}
}
/**
* @brief LVGL演示
* @param 无
* @return 无
*/
void lv_mainstart(void)
{
/* 动态获取屏幕大小 */
scr_act_width = lv_obj_get_width(lv_scr_act());
scr_act_height = lv_obj_get_height(lv_scr_act());
/* 父对象 */
parent_obj = lv_obj_create(lv_scr_act()); /* 创建父对象 */
/* 设置父对象的大小 */
lv_obj_set_size(parent_obj, scr_act_width * 2/3, scr_act_height * 2/3);
/* 设置父对象的位置 */
lv_obj_align(parent_obj, LV_ALIGN_TOP_MID, 0, 0);
/* 设置父对象的背景色:浅蓝色 */
lv_obj_set_style_bg_color(parent_obj, lv_color_hex(0x99ccff), 0);
/* 为父对象添加事件:长按触发 */
lv_obj_add_event_cb(parent_obj, obj_event_cb, LV_EVENT_LONG_PRESSED, NULL);
/* 子对象 */
child_obj = lv_obj_create(parent_obj); /* 创建子对象 */
/* 设置子对象的大小 */
lv_obj_set_size(child_obj, scr_act_width / 3, scr_act_height / 3);
/* 设置子对象的位置:居中 */
lv_obj_align(child_obj, LV_ALIGN_CENTER, 0, 0);
/* 设置子对象的背景色:深蓝色 */
lv_obj_set_style_bg_color(child_obj, lv_color_hex(0x003366), 0);
/* 为子对象添加事件:按下释放后触发 */
lv_obj_add_event_cb(child_obj, obj_event_cb, LV_EVENT_CLICKED, NULL);
}
① 创建对象并添加事件回调。我们首先获取动态屏幕的大小,以适配不同尺寸的屏幕,然后再分别创建父对象和子对象,并为它们添加事件回调;
② 处理事件回调。在回调函数中,我们首先获取事件的触发源,然后判断是父对象还是子对象触发的事件,若是前者,则重新设置父对象的位置,使其居中对齐,此时,子对象的位置也会随之变化;若是后者,则重新设置子对象的位置,使其右侧居中,并且向X轴的正半轴偏移 100 像素,此时,子对象超出父对象的部分默认不可见。