LVGL部件篇:基础对象(lv_obj)

目录

简介

基础对象的作用  

作为背景装饰

辅助布局 

界面切换 

基础对象的相关知识  

基础对象的 API 函数 

基础对象部件的实验

简介

基础对象本身就是一个小部件,当它被创建出来之后,其呈现出一个矩形。除此之外,基础对象还是其他小部件的父类,所有部件的位置、大小等基本属性都是归基础对象管理的。

基础对象的作用  

基础对象的作用有四个:
① 管理其他部件的基本属性;
② 作为背景装饰;
③ 辅助布局;
④ 界面切换。
第一个作用我们在LVGL基础知识(入门必看) 中已经介绍过,本章重点介绍基础对象的其他作用。

作为背景装饰

当基础对象被创建出来后,它默认是一个圆角矩阵:
 lv_obj_t * obj = lv_obj_create(lv_scr_act());

 

在设计较为复杂的 GUI 界面时,不同功能的模块之间需要清晰地划分区域,此时,我们可以使用基础对象作为背景,对不同的区域进行划分。

 

辅助布局 

当  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 设计中,我们可以利用上述的特性,实现界面的切换,示意图如下所示:

由上图可知,基础对象 12 分别用于管理界面 12,它们之中存在一些子对象(例如开关),当用户需要切换界面时,只需切换容器即可。这一点非常的重要,尤其是在我们做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_HIDDEN1L << 0 (0x0001)对象是否隐藏。隐藏时不可见但仍存在于布局中。
LV_OBJ_FLAG_CLICKABLE1L << 1 (0x0002)对象是否可以点击。如果设为不可点击,则不会响应点击事件。
LV_OBJ_FLAG_CLICK_FOCUSABLE1L << 2 (0x0004)点击时是否获取焦点。适用于需要切换焦点的交互控件。
LV_OBJ_FLAG_CHECKABLE1L << 3 (0x0008)对象是否可选中,例如按钮或复选框。
LV_OBJ_FLAG_SCROLLABLE1L << 4 (0x0010)对象是否可滚动。适用于滚动容器。
LV_OBJ_FLAG_SCROLL_ELASTIC1L << 5 (0x0020)滚动是否有弹性效果,通常用于提升用户体验。
LV_OBJ_FLAG_SCROLL_MOMENTUM1L << 6 (0x0040)滚动是否具有惯性效果(滑动后继续滚动一段距离)。
LV_OBJ_FLAG_SCROLL_ONE1L << 7 (0x0080)是否只能滚动一个元素(例如单项选择列表)。
LV_OBJ_FLAG_SCROLL_CHAIN_HOR1L << 8 (0x0100)水平滚动是否可以链式滚动(与父对象联动)。
LV_OBJ_FLAG_SCROLL_CHAIN_VER1L << 9 (0x0200)垂直滚动是否可以链式滚动(与父对象联动)。
LV_OBJ_FLAG_SCROLL_CHAIN(1L << 8) | (1L << 9)水平和垂直方向都支持链式滚动。
LV_OBJ_FLAG_SCROLL_ON_FOCUS1L << 10 (0x0400)当对象获得焦点时自动滚动到可见区域。
LV_OBJ_FLAG_SCROLL_WITH_ARROW1L << 11 (0x0800)是否可以通过方向键滚动。
LV_OBJ_FLAG_SNAPPABLE1L << 12 (0x1000)对象是否可以对齐到某个位置,例如网格或边界。
LV_OBJ_FLAG_PRESS_LOCK1L << 13 (0x2000)按下对象后,是否锁定对象直到释放按键。
LV_OBJ_FLAG_EVENT_BUBBLE1L << 14 (0x4000)事件是否可以冒泡到父对象,用于事件传播机制。
LV_OBJ_FLAG_GESTURE_BUBBLE1L << 15 (0x8000)手势事件是否可以冒泡到父对象。
LV_OBJ_FLAG_ADV_HITTEST1L << 16 (0x10000)使用高级命中测试,判断点击是否在特定区域内。
LV_OBJ_FLAG_IGNORE_LAYOUT1L << 17 (0x20000)忽略布局管理,允许对象独立定位。
LV_OBJ_FLAG_FLOATING1L << 18 (0x40000)对象是否浮动在布局之上。
LV_OBJ_FLAG_OVERFLOW_VISIBLE1L << 19 (0x80000)内容溢出时是否仍然显示溢出的部分。
LV_OBJ_FLAG_LAYOUT_1/21L << 23/24用于指定布局类型的标志位。
LV_OBJ_FLAG_WIDGET_1/21L << 25/26用于定义某些特定小部件的标志位。
LV_OBJ_FLAG_USER_1/2/3/41L << 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 函数 

LVGL 官方提供了很多与基础对象相关 API 函数:
函数名称功能主要参数返回值

lv_obj_create()

创建一个基础对象(矩形)。

parent: 父对象指针。如果为 NULL,创建屏幕对象。

新创建对象的指针。

lv_obj_set_user_data()

设置对象的用户数据字段 (user_data) 。

obj: 对象指针;
user_data: 用户自定义数据,类型为 void *

无返回值。

lv_obj_has_flag()

检查对象是否设置了指定标志。

obj: 对象指针;
flag: 要检查的标志。

truefalse

lv_obj_has_flag_any()

检查对象是否设置了任意一个指定标志(可以是多个的组合)。

obj: 对象指针;
flags: 要检查的标志(多个标志可按位或操作)。

truefalse

lv_obj_get_state()

获取对象的当前状态。

obj: 对象指针。

返回对象的状态,类型为 lv_state_t

lv_obj_has_state()

检查对象是否处于指定状态。

obj: 对象指针;
state: 要检查的状态。

truefalse

lv_obj_get_group()

获取对象所属的组,用于输入焦点管理。

obj: 对象指针。

返回对象所属的组指针;若无组,返回 NULL

lv_obj_get_user_data()

获取对象的用户数据。

obj: 对象指针。

返回用户数据(之前设置的 void *)。

lv_obj_allocate_spec_attr()

为对象分配特殊属性数据(spec_attr),确保该内存已分配。

obj: 对象指针。

无返回值。

lv_obj_check_type()

检查对象类型是否匹配某种类型。

obj: 对象指针;
class: 要检查的类型。

truefalse

lv_obj_has_class()

检查对象是否属于指定类或其派生类。

obj: 对象指针;
class: 要检查的类。

truefalse

lv_obj_get_class()

获取对象所属的类信息。

obj: 对象指针。

返回对象所属的类信息指针。

lv_obj_is_valid()

检查对象是否仍然有效(未被删除)。

obj: 对象指针。

truefalse

基础对象部件的实验

本实验主要测试基础对象 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 像素,此时,子对象超出父对象的部分默认不可见。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值