LVGL系列(四)概述 之 位置、尺寸和布局

“本文大部分内容来自LVGL官方文档,手翻版,如有错误欢迎指正。”

系列文章目录

一、LVGL系列(一) 一文了解LVGL的学习路线 轻松了解LVGL的全部 

二、LVGL系列(二)之一 LVGL必读介绍  为什么要学习LVGL

       LVGL系列(二)之二 LVGL常见问题解答 整理自官方文档

二、LVGL系列(三)LVGL仿真环境的搭建(WIN下)

        2.1 VS下搭建LVGL仿真环境

        2.1 如何在仿真环境下运行自己的代码

三、LVGL系列(三) LVGL移植教程

四、LVGL系列(四)概述

        4.1 对象 LVGL核心概念

        4.2  位置、尺寸和布局

五、LVGL系列(五)部件

六、LVGL系列(六)布局

文章目录

目录

系列文章目录

文章目录

一、概览  

1.1 单位(Units)

1.2 盒子模型 Boxing model

1.3 Important notes

1.4 延迟坐标推算 Postponed coordinate calculation

1.5 移除样式 Removing styles

二、 位置(Position)

2.1 简单方式 Simple way 

2.2 对齐(Align)

三 、 尺寸(Size)

3.1 简单方法(Simple way)

四、通过样式实现

五、 转换 Translation

六、变换Transformation

6.1 最大最小尺寸(Min and Max size)

七、 布局Layout

7.1 概览(Overview)

7.2 标志 (Flags)

7.3 Adding new layouts(添加新的布局)



一、概览  

        跟LVGL其他的部分相似,坐标设定的概念灵感来自于CSS。并不是完全的按照其标准实现,而是实现了一小部分功能,会有一些小调整。简而言之,这意味着:

  • 坐标(size, position, layouts, etc)的设定是通过styles实现的。
  • 支持最小宽度、最大宽度、最低高度、最大高度。
  • 具有像素、百分比和“内容”单位。
  • x=0; y=0 的坐标意味着在父类的左上角加上左上填充加上边框宽度。
  • 高度/宽度是指全尺寸,内容区域随着填充的和边框的宽度增加而减小。
  • 支持flexbox和grid布局的子集。

1.1 单位(Units

  • 像素:简单的说在像素中的一个位置,一个简单的整数可代替像素的位置。例如:lv_obj_set_x(btn,  10)
  • 百分比:对象或者它父类的百分比(依赖于父类的大小)。函数lv_pct(value) 能向百分比传递一个值。例如:lv_obj_set_width(btn,  lv_pct(50))  
  • LV_SIZE_CONTENT: 用于设置一个对象和它子对象高度和宽度的特殊值。它类似于CSS里的自动设置。例如:lv_obj_set_width(btn,  LV_SIZE_CONTENT).

1.2 盒子模型 Boxing model

        LVGL 遵循 CSS的 border-box 模型. 一个对象的“box”由以下部分组成:An object's "box" is built from the following parts:

  • 边界框(bounding box): 元素的高度和宽度。the width/height of the elements.
  • 边界宽度(border width):边界的宽度,边界框的宽度。the width of the border.
  • 填充(padding):在一个对象和它子对象之间的空间。: space between the sides of the object and its children.
  • 内容(content): 内容区域的大小是除去边界框、边界宽度、填充区域剩下的区域。

边界在边界框里面绘制,在边界内部,LVGL保持填充区域以放置子对象。轮廓在边界框外面绘制。

1.3 Important notes

本节介绍LVGL行为可能意外的特殊情况。

1.4 延迟坐标推算 Postponed coordinate calculation

        LVGL不会立即重新计算所有坐标的变化。这样做是为了提升性能。相反,有些对象被标记为"dirty"并且在重新绘制屏幕之前,LVGL会检查是否有一些"dirty"。如果是,LVGL就会刷新他们的位置、尺寸和布局。

        换句话说, 如果你需要获取一个对象的坐标而且它的坐标刚刚发生改变,需要强制LVGL重新计算坐标。可以调用lv_obj_update_layout(obj)来实现。

    尺寸和位置可能会依赖与父类或者布局。因此lv_obj_update_layout(obj).会重新计算在屏幕上的所有对象的坐标。

1.5 移除样式 Removing styles

        正如Using style部分所述:坐标同样可以通过style参数的方式进行设置。更准确地说,在后台,每个与样式坐标相关的属性都存储为样式属性。如果你使用了lv_obj_set_x(obj,  20)LVGL将在对象的本地样式中保存x=20。这是一个内部的工作机制,跟你使用的LVGL没有太大关系。但是,有一种情况你需要知道。如果一个对象的样式被移除,通过:

1.	lv_obj_remove_style_all (obj)

或者

1.	lv_obj_remove_style(obj,   NULL , LV_PART_MAIN);

        在此之前设置的坐标也会被移除。

例如:

1.	/*The size of obj1 will be set back to the default in the end*/
2.	lv_obj_set_size(obj1, 200, 100); /*Now obj1 has 200;100 size*/
3.	lv_obj_remove_style_all(obj1); /*It removes the set sizes*/
4.	/*obj2 will have 200;100 size in the end */
5.	lv_obj_remove_style_all(obj2);
6.	lv_obj_set_size(obj2, 200, 100);

二、 位置Position

2.1 简单方式 Simple way 

        简单的给一个对象设置x和y坐标可以通过下列方法:

1.	lv_obj_set_x(obj, 10);
2.	lv_obj_set_y(obj, 20);
3.	lv_obj_set_pos(obj, 10, 20); //Or in one function

        默认情况下,x和y坐标从父级内容区域的左上角测量。例如:如果父对象在每个边上都有5个像素的填充区域,上面的代码会把对象放在(15,25),这是因为内容区域是在填充之后开始的。

        如果根据父对象的内容区域的大小计算百分比的值:

1.	lv_obj_set_x(btn,  lv_pct(10));  //x = 10 % of parant content area width

2.2 对齐(Align

        在某些情况下,可以很方便的修改位置标的默认原点。如果原点被更改,例如:对于左下角,(0,0)意味着:与右下角对齐。改变原点可以通过:

1.	lv_obj_set_align(obj,  align);

        改变排列并设置新的坐标:

1.	lv_obj_align(obj, align, x, y);

        下列的一些排列位置可以使用:

  • LV_ALIGN_TOP_LEFT
  • LV_ALIGN_TOP_MID
  • LV_ALIGN_TOP_RIGHT
  • LV_ALIGN_BOTTOM_LEFT
  • LV_ALIGN_BOTTOM_MID
  • LV_ALIGN_BOTTOM_RIGHT
  • LV_ALIGN_LEFT_MID
  • LV_ALIGN_RIGHT_MID
  • LV_ALIGN_CENTER

        将父对象和子对象对齐是十分常见的,因此对于这个功能有一个专门对应的方法:

1.	lv_obj_center(obj);
2.	
3.	//Has the same effect
4.	lv_obj_align(obj,  LV_ALIGN_CENTER,  0,  0);

        如果父对象的的尺寸发生了变化,子对象的对齐设置和位置会自动重新的排列。

上面介绍的函数将对象与它的父类对齐。然而,他也有可能与一个任意的对象对齐。

1.	lv_obj_align_to(obj_to_align, reference_obj, align, x, y);

除了上面的一些对齐方式之外,下面的一些选项可以用来将对象与参考对象的外边对齐:

  • LV_ALIGN_OUT_TOP_LEFT
  • LV_ALIGN_OUT_TOP_MID
  • LV_ALIGN_OUT_TOP_RIGHT
  • LV_ALIGN_OUT_BOTTOM_LEFT
  • LV_ALIGN_OUT_BOTTOM_MID
  • LV_ALIGN_OUT_BOTTOM_RIGHT
  • LV_ALIGN_OUT_LEFT_TOP
  • LV_ALIGN_OUT_LEFT_MID
  • LV_ALIGN_OUT_LEFT_BOTTOM
  • LV_ALIGN_OUT_RIGHT_TOP
  • LV_ALIGN_OUT_RIGHT_MID
  • LV_ALIGN_OUT_RIGHT_BOTTOM

        例如:要对齐按钮上方的标签并且使标签水平居中对齐:

1.	lv_obj_align_to(label,  btn,  LV_ALIGN_OUT_TOP_MID,  0,  -10);

请注意:不像lv_obj_align()一样,lv_obj_align_to()并不能在它的坐标或者参考对象的坐标发生改变后重新对齐。

三 、 尺寸(Size)

3.1 简单方法(Simple way

        一个对象的宽度和高度也可以轻松设置,方法如下:

1.	lv_obj_set_width(obj, 200);
2.	lv_obj_set_height(obj, 100);
3.	lv_obj_set_size(obj, 200, 100); //Or in one function

        百分比值是基于父对象的内容区域大小计算的。例如:要将对象的高度设置成屏幕的高度

1.	lv_obj_set_height(obj,  lv_pct(100))

        尺寸设置支持单值:LV_SIZE_CONTENT 。这意味着对象在各自的方向上的尺寸大小将设置为它子类的大小。请注意:只考虑右下的子类,而左上的将会保持裁剪。这种限制让对象的行为更加可预测。

   具有LV_OBJ_FLAG_HIDDEN or LV_OBJ_FLAG_FLOATING属性的对象会被LV_SIZE_CONTENT算法忽略。

        上面的函数不光可以设置对象边界的尺寸,而且也可以设置内容区域的尺寸。这意味着对象的边界在填充后大于设置的尺寸。

1.	lv_obj_set_content_width(obj, 50); //The actual width: padding left + 50 + padding right
2.	lv_obj_set_content_height(obj, 30); //The actual width: padding top + 30 + padding bottom

可通过以下功能获取边界框和内容区域的大小:

1.	lv_coord_t w = lv_obj_get_width(obj);
2.	lv_coord_t h = lv_obj_get_height(obj);
3.	lv_coord_t content_w = lv_obj_get_content_width(obj);
4.	lv_coord_t content_h = lv_obj_get_content_height(obj);

四、通过样式实现

        位置、尺寸、对齐方式等属性是样式属性。为了简单起见,上面所描述的简单函数隐藏了与样式相关的代码,并且在本地样式中设置了对象的位置、大小、和对齐方式几个属性。

        但是,使用样式来设置坐标有非常多的优点:

  • 可以一起轻松设置多个对象的宽度/高度等属性。例如:设置所有的滑块100×10像素大小。
  • 可以在一个位置修改属性值。
  • 这些值可以被其他样式覆盖。例如在默认状态下style_btn 设置对象为100×50,但是style_full_width 函数能够覆盖对象的宽度特性。
  • 对象可以在不同的状态下具有不同的位置和大小。例如:在默认状态下为100px 而在LV_STATE_PRESSED 下为120px。
  • 样式传递可以使坐标变化平滑。

以下时使用样式来设置对象大小的例子:

1.	static lv_style_t style;
2.	lv_style_init(&style);
3.	lv_style_set_width(&style, 100);
4.	lv_obj_t * btn = lv_btn_create(lv_scr_act());
5.	lv_obj_add_style(btn, &style, LV_PART_MAIN);

        正如你即将在下面看到的一样,还有一些其他关于设置位置和尺寸的强大功能。然而为了保持LVGl的API的简洁性,只有最常见的坐标设置具有最简版本,对于更复杂的属性设置通过样式来实现。

五、 转换 Translation

        比方说:现在有相邻的3个按钮,它们的位置设置像上面说的一样。现在,你想在按钮被按下的时,让按钮向上一点。

        实现这个设置的一个方式是给按压状态设置一个新的Y坐标:

1.	static lv_style_t style_normal;
2.	lv_style_init(&style_normal);
3.	lv_style_set_y(&style_normal, 100);
4.	static lv_style_t style_pressed;
5.	lv_style_init(&style_pressed);
6.	lv_style_set_y(&style_pressed, 80);
7.	lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
8.	lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);
9.	lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
10.	lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);
11.	lv_obj_add_style(btn3, &style_normal, LV_STATE_DEFAULT);
12.	lv_obj_add_style(btn3, &style_pressed, LV_STATE_PRESSED);

         可以通过上面的的方式实现这个需求,但是,由于这是硬编码实现的,看起来不够丝滑。如果按钮不在y=100,style_pressed不会按照预期的那样工作。为了解决这个问题可以使用Translation来实现:

1.	static lv_style_t style_normal;
2.	lv_style_init(&style_normal);
3.	lv_style_set_y(&style_normal, 100);
4.	static lv_style_t style_pressed;
5.	lv_style_init(&style_pressed);
6.	lv_style_set_translate_y(&style_pressed, -20);
7.	lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
8.	lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);
9.	lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
10.	lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);
11.	lv_obj_add_style(btn3, &style_normal, LV_STATE_DEFAULT);
12.	lv_obj_add_style(btn3, &style_pressed, LV_STATE_PRESSED);

        通过上面的操作变换(Translation)被应用于对象的当前位置。

        百分比值也用于(Translation)。对象的大小与百分比有关(不会作用于父类)。比如:lv_pct(50)可以使对象移动到它的宽或高一半的距离。

在布局计算之后转换(translation)才会应用。因此即使已经布局的对象的位置一样可以被转换。

转换(translation)实际上上是移动了对象(这本文中translation叫平移更加合适)。这就意味着它可以使滚动条和LV_SIZE_CONTENT对象对位置改变做出反应。

六、变换Transformation

        与位置属性相似,尺寸属性也可以相对于当前尺寸大小改变。变换后的宽度和高度将会添加到对象的两边。这意味着在宽度10个像素的变换实际上使对象扩展到2×10个像素的宽度。

        不像位置变换一样,尺寸变换不会让对象真正的变大。换句话说,滚动条、布局、LV_SIZE_CONTENT不会考虑转换大小。因此如果仅仅是一个视觉效果使用尺寸变化更合适。

        下面的代码使一个按钮在按下时变大:

1.	static lv_style_t  style_pressed; lv_style_init(&style_pressed);
2.	lv_style_set_transform_width(&style_pressed,  10);
3.	lv_style_set_transform_height(&style_pressed,  10);
4.	
5.	lv_obj_add_style(btn,  &style_pressed,  LV_STATE_PRESSED);

        与位置相似,大小也可以根据当前大小进行更改。转换后的宽度和高度被添加到对象的两边。这意味着10像素的转换宽度使对象宽2x10像素。

        与位置平移不同,这种大小的转换并不会让对象真正的变大。换句话说,滑块、布局、LV_SIZE_CONTENT将不考虑转换后的大小。因此这样的尺寸变化只是一个视觉效果。

下面的代码可以实现当按钮被按下时变大的效果:

1.	static lv_style_t  style_pressed; lv_style_init(&style_pressed); 
2.	lv_style_set_transform_width(&style_pressed,  10);
3.	lv_style_set_transform_height(&style_pressed,  10);
4.	
5.	lv_obj_add_style(btn,  &style_pressed,  LV_STATE_PRESSED);

6.1 最大最小尺寸(Min and Max size

        类似于CSS,LVGL也支持min-width, max-width, min-height max-height.他们可以限制对象尺寸的范围。如果这些值由百分比或者LV_SIZE_CONTENT设置,这些限制非常有效

1.	static lv_style_t style_max_height;
2.	lv_style_init(&style_max_height);
3.	lv_style_set_y(&style_max_height, 200);
4.	lv_obj_set_height(obj, lv_pct(100));
5.	lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //Limit the height to 200 px

还可以使用相对于父类内容区域大小的百分比值:

1.	static lv_style_t style_max_height;
2.	lv_style_init(&style_max_height);
3.	lv_style_set_y(&style_max_height, lv_pct(50));
4.	lv_obj_set_height(obj, lv_pct(100));
5.	lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //Limit the height to␣half parent heigh

七、 布局Layout

7.1 概览(Overview

        布局能够更新一个对象的子类的位置和尺寸大小。他们能够使子类自动的按照一行或者一列的方式排布,或者更加复杂的方式。

        布局设置的位置和大小将覆盖正常情况下x,y,高度、宽度的设置。

        每个布局只有一个相同的功能:lv_obj_set_layout(obj,  <LAYOUT_NAME>)设置对象上的布局。有关父级类和子类的进一步设置,请参阅给定布局的文档。

7.2内置布局Built-in layout

LVGL具有两个非常强大的布局:

  • Flexbox
  • Grid

两者都深受同名 CSS 布局的启发。

7.2 标志 (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/clear_flag(obj,  FLAG)

7.3 Adding new layouts(添加新的布局)

LVGL可以通过如下自定义布局自由的扩展:

1.	uint32_t MY_LAYOUT;
2.	...
3.	MY_LAYOUT = lv_layout_register(my_layout_update, &user_data);
4.	...
5.	void my_layout_update(lv_obj_t * obj, void * user_data)
6.	{
7.	   /*Will be called automatically if required to reposition/resize the children of "obj" */
8.	}

还可以添加自定义风格属性,这些属性可以在更新回调函数中获取,例如:

1.	uint32_t MY_PROP;
2.	...
3.	LV_STYLE_MY_PROP = lv_style_register_prop();
4.	...
5.	static inline void lv_style_set_my_prop(lv_style_t * style, uint32_t value)
6.	{
7.	lv_style_value_t v = {
8.	.num = (int32_t)value
9.	};
10.	lv_style_set_prop(style, LV_STYLE_MY_PROP, v);
11.	}

  • 12
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪有万里山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值