弹性布局 (Flex)¶
概述¶
弹性布局(简称 Flex)是 CSS Flexbox 的一个子集。
它可以将项目排列为行或列(轨道),处理换行,调整项目和轨道之间的间距,处理扩展以使项目根据最小/最大宽度和高度填充剩余空间。
要将对象设置为弹性容器,请调用 lv_obj_set_layout(obj, LV_LAYOUT_FLEX)。
请注意,LVGL 的弹性布局功能需要在 lv_conf.h 中通过 LV_USE_FLEX 全局启用。
术语¶
轨道:行或列
主方向:行或列,即项目排列的方向
交叉方向:与主方向垂直的方向
换行:如果轨道中没有更多空间,则开始新轨道
扩展:如果在项目上设置了扩展,它将扩展以填充轨道上的剩余空间。 可用空间将根据项目的扩展值按比例分配(值越大,分配的空间越多)
间隙:行和列之间或轨道上的项目之间的空间
简单接口¶
通过以下函数,可以在任何父对象上设置弹性布局。
弹性流¶
lv_obj_set_flex_flow(obj, flex_flow)
flex_flow 的可能值包括:
LV_FLEX_FLOW_ROW将子项排列为一行,不换行LV_FLEX_FLOW_COLUMN将子项排列为一列,不换行LV_FLEX_FLOW_ROW_WRAP将子项排列为一行,支持换行LV_FLEX_FLOW_COLUMN_WRAP将子项排列为一列,支持换行LV_FLEX_FLOW_ROW_REVERSE将子项排列为一行,不换行,但顺序反转LV_FLEX_FLOW_COLUMN_REVERSE将子项排列为一列,不换行,但顺序反转LV_FLEX_FLOW_ROW_WRAP_REVERSE将子项排列为一行,支持换行,但顺序反转LV_FLEX_FLOW_COLUMN_WRAP_REVERSE将子项排列为一列,支持换行,但顺序反转
弹性对齐¶
使用 lv_obj_set_flex_align(obj, main_place, cross_place, track_cross_place) 管理子项的排列。
main_place决定如何在主轴上分配轨道中的项目。例如,在LV_FLEX_FLOW_ROW_WRAP中将项目对齐到右侧。(在 CSS 中称为justify-content)cross_place决定如何在交叉轴上分配轨道中的项目。例如,如果项目具有不同的高度,将它们对齐到轨道的底部。(在 CSS 中称为align-items)track_cross_place决定如何分配轨道。(在 CSS 中称为align-content)
可能的值包括:
LV_FLEX_ALIGN_START表示水平左对齐或垂直顶部对齐。(默认值)LV_FLEX_ALIGN_END表示水平右对齐或垂直底部对齐。LV_FLEX_ALIGN_CENTER居中对齐。LV_FLEX_ALIGN_SPACE_EVENLY项目分布均匀,任何两个项目之间的间距(以及与边缘的间距)相等。不适用于track_cross_place。LV_FLEX_ALIGN_SPACE_AROUND项目在轨道中均匀分布,周围间距相等。 注意,视觉上间距并不相等,因为所有项目两侧的间距相等。 第一个项目与容器边缘之间有一个单位的间距,但与下一个项目之间有两个单位的间距,因为下一个项目也有自己的间距。不适用于track_cross_place。LV_FLEX_ALIGN_SPACE_BETWEEN项目在轨道中均匀分布:第一个项目在起始线,最后一个项目在结束线。不适用于track_cross_place。
弹性扩展¶
弹性扩展可用于使一个或多个子项填充轨道上的可用空间。当多个子项具有扩展参数时,可用空间将按扩展值的比例分配。 例如,有 400 像素的剩余空间和 4 个对象具有扩展值:
A的扩展值 = 1B的扩展值 = 1C的扩展值 = 2
A 和 B 的大小为 100 像素,C 的大小为 200 像素。
可以使用 lv_obj_set_flex_grow(child, value) 在子项上设置弹性扩展。value 需要大于 1,或者设置为 0 以禁用子项的扩展。
样式接口¶
所有与弹性相关的值在底层都是样式属性,可以像其他样式属性一样使用。以下是与弹性相关的样式属性:
FLEX_FLOWFLEX_MAIN_PLACEFLEX_CROSS_PLACEFLEX_TRACK_PLACEFLEX_GROW
内部填充¶
要修改弹性布局在对象之间插入的最小空间,可以在弹性容器样式上设置以下属性:
pad_row设置行之间的填充。pad_column设置列之间的填充。
例如,如果不希望对象之间有任何填充,可以使用:lv_style_set_pad_column(&row_container_style, 0)。
其他功能¶
RTL¶
如果容器的基本方向设置为 LV_BASE_DIR_RTL,则在 ROW 布局中 LV_FLEX_ALIGN_START 和 LV_FLEX_ALIGN_END 的含义将交换。即 START 将表示右对齐。
在 ROW 布局中的项目,以及 COLUMN 布局中的轨道,将从右到左排列。
新轨道¶
可以使用 lv_obj_add_flag(child, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK) 强制弹性布局将项目放入新行。
示例¶
使用弹性盒的简单行和列布局¶
C code
GitHub#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* A simple row and a column layout with flexbox
*/
void lv_example_flex_1(void)
{
/*Create a container with ROW flex direction*/
lv_obj_t * cont_row = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont_row, 300, 75);
lv_obj_align(cont_row, LV_ALIGN_TOP_MID, 0, 5);
lv_obj_set_flex_flow(cont_row, LV_FLEX_FLOW_ROW);
/*Create a container with COLUMN flex direction*/
lv_obj_t * cont_col = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont_col, 200, 150);
lv_obj_align_to(cont_col, cont_row, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
lv_obj_set_flex_flow(cont_col, LV_FLEX_FLOW_COLUMN);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_obj_t * obj;
lv_obj_t * label;
/*Add items to the row*/
obj = lv_btn_create(cont_row);
lv_obj_set_size(obj, 100, LV_PCT(100));
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Item: %u", i);
lv_obj_center(label);
/*Add items to the column*/
obj = lv_btn_create(cont_col);
lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Item: %"LV_PRIu32, i);
lv_obj_center(label);
}
}
#endif
#
# A simple row and a column layout with flexbox
#
# Create a container with ROW flex direction
cont_row = lv.obj(lv.scr_act())
cont_row.set_size(300, 75)
cont_row.align(lv.ALIGN.TOP_MID, 0, 5)
cont_row.set_flex_flow(lv.FLEX_FLOW.ROW)
# Create a container with COLUMN flex direction
cont_col = lv.obj(lv.scr_act())
cont_col.set_size(200, 150)
cont_col.align_to(cont_row, lv.ALIGN.OUT_BOTTOM_MID, 0, 5)
cont_col.set_flex_flow(lv.FLEX_FLOW.COLUMN)
for i in range(10):
# Add items to the row
obj = lv.btn(cont_row)
obj.set_size(100, lv.pct(100))
label = lv.label(obj)
label.set_text("Item: {:d}".format(i))
label.center()
# Add items to the column
obj = lv.btn(cont_col)
obj.set_size(lv.pct(100), lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text("Item: {:d}".format(i))
label.center()
在行中排列项目,带有换行和均匀间距¶
C code
GitHub#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Arrange items in rows with wrap and place the items to get even space around them.
*/
void lv_example_flex_2(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_flex_flow(&style, LV_FLEX_FLOW_ROW_WRAP);
lv_style_set_flex_main_place(&style, LV_FLEX_ALIGN_SPACE_EVENLY);
lv_style_set_layout(&style, LV_LAYOUT_FLEX);
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_add_style(cont, &style, 0);
uint32_t i;
for(i = 0; i < 8; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
lv_obj_t * label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%"LV_PRIu32, i);
lv_obj_center(label);
}
}
#endif
#
# Arrange items in rows with wrap and place the items to get even space around them.
#
style = lv.style_t()
style.init()
style.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
style.set_flex_main_place(lv.FLEX_ALIGN.SPACE_EVENLY)
style.set_layout(lv.LAYOUT_FLEX.value)
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.add_style(style, 0)
for i in range(8):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text("{:d}".format(i))
label.center()
演示弹性增长¶
C code
GitHub#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Demonstrate flex grow.
*/
void lv_example_flex_3(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);
lv_obj_t * obj;
obj = lv_obj_create(cont);
lv_obj_set_size(obj, 40, 40); /*Fix size*/
obj = lv_obj_create(cont);
lv_obj_set_height(obj, 40);
lv_obj_set_flex_grow(obj, 1); /*1 portion from the free space*/
obj = lv_obj_create(cont);
lv_obj_set_height(obj, 40);
lv_obj_set_flex_grow(obj, 2); /*2 portion from the free space*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, 40, 40); /*Fix size. It is flushed to the right by the "grow" items*/
}
#endif
#
# Demonstrate flex grow.
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW)
obj = lv.obj(cont)
obj.set_size(40, 40) # Fix size
obj = lv.obj(cont)
obj.set_height(40)
obj.set_flex_grow(1) # 1 portion from the free space
obj = lv.obj(cont)
obj.set_height(40)
obj.set_flex_grow(2) # 2 portion from the free space
obj = lv.obj(cont)
obj.set_size(40, 40) # Fix size. It is flushed to the right by the "grow" items
演示弹性增长¶
C code
GitHub#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Reverse the order of flex items
*/
void lv_example_flex_4(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN_REVERSE);
uint32_t i;
for(i = 0; i < 6; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 100, 50);
lv_obj_t * label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Item: %"LV_PRIu32, i);
lv_obj_center(label);
}
}
#endif
#
# Reverse the order of flex items
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.COLUMN_REVERSE)
for i in range(6):
obj = lv.obj(cont)
obj.set_size(100, 50)
label = lv.label(obj)
label.set_text("Item: " + str(i))
label.center()
演示列和行间隙样式属性¶
C code
GitHub#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
static void row_gap_anim(void * obj, int32_t v)
{
lv_obj_set_style_pad_row(obj, v, 0);
}
static void column_gap_anim(void * obj, int32_t v)
{
lv_obj_set_style_pad_column(obj, v, 0);
}
/**
* Demonstrate the effect of column and row gap style properties
*/
void lv_example_flex_5(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW_WRAP);
uint32_t i;
for(i = 0; i < 9; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
lv_obj_t * label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%"LV_PRIu32, i);
lv_obj_center(label);
}
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, cont);
lv_anim_set_values(&a, 0, 10);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_exec_cb(&a, row_gap_anim);
lv_anim_set_time(&a, 500);
lv_anim_set_playback_time(&a, 500);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, column_gap_anim);
lv_anim_set_time(&a, 3000);
lv_anim_set_playback_time(&a, 3000);
lv_anim_start(&a);
}
#endif
def row_gap_anim(obj, v):
obj.set_style_pad_row(v, 0)
def column_gap_anim(obj, v):
obj.set_style_pad_column(v, 0)
#
# Demonstrate the effect of column and row gap style properties
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(9):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text(str(i))
label.center()
a_row = lv.anim_t()
a_row.init()
a_row.set_var(cont)
a_row.set_values(0, 10)
a_row.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_row.set_time(500)
a_row.set_playback_time(500)
a_row.set_custom_exec_cb(lambda a,val: row_gap_anim(cont,val))
lv.anim_t.start(a_row)
a_col = lv.anim_t()
a_col.init()
a_col.set_var(cont)
a_col.set_values(0, 10)
a_col.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_col.set_time(3000)
a_col.set_playback_time(3000)
a_col.set_custom_exec_cb(lambda a,val: column_gap_anim(cont,val))
lv.anim_t.start(a_col)
RTL 基础方向更改项目顺序¶
C code
GitHub#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* RTL base direction changes order of the items.
* Also demonstrate how horizontal scrolling works with RTL.
*/
void lv_example_flex_6(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_style_base_dir(cont, LV_BASE_DIR_RTL, 0);
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW_WRAP);
uint32_t i;
for(i = 0; i < 20; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
lv_obj_t * label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%"LV_PRIu32, i);
lv_obj_center(label);
}
}
#endif
#
# RTL base direction changes order of the items.
# Also demonstrate how horizontal scrolling works with RTL.
#
cont = lv.obj(lv.scr_act())
cont.set_style_base_dir(lv.BASE_DIR.RTL,0)
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(20):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text(str(i))
label.center()
API¶
Enums
-
enum
lv_flex_align_t¶ Values:
-
enumerator
LV_FLEX_ALIGN_START¶
-
enumerator
LV_FLEX_ALIGN_END¶
-
enumerator
LV_FLEX_ALIGN_CENTER¶
-
enumerator
LV_FLEX_ALIGN_SPACE_EVENLY¶
-
enumerator
LV_FLEX_ALIGN_SPACE_AROUND¶
-
enumerator
LV_FLEX_ALIGN_SPACE_BETWEEN¶
-
enumerator
-
enum
lv_flex_flow_t¶ Values:
-
enumerator
LV_FLEX_FLOW_ROW¶
-
enumerator
LV_FLEX_FLOW_COLUMN¶
-
enumerator
LV_FLEX_FLOW_ROW_WRAP¶
-
enumerator
LV_FLEX_FLOW_ROW_REVERSE¶
-
enumerator
LV_FLEX_FLOW_ROW_WRAP_REVERSE¶
-
enumerator
LV_FLEX_FLOW_COLUMN_WRAP¶
-
enumerator
LV_FLEX_FLOW_COLUMN_REVERSE¶
-
enumerator
LV_FLEX_FLOW_COLUMN_WRAP_REVERSE¶
-
enumerator
Functions
-
LV_EXPORT_CONST_INT(LV_OBJ_FLAG_FLEX_IN_NEW_TRACK)¶
-
void
lv_flex_init(void)¶ Initialize a flex layout the default values
- Parameters
flex -- pointer to a flex layout descriptor
-
void
lv_obj_set_flex_flow(lv_obj_t *obj, lv_flex_flow_t flow)¶ Set hot the item should flow
- Parameters
flex -- pointer to a flex layout descriptor
flow -- an element of
lv_flex_flow_t.
-
void
lv_obj_set_flex_align(lv_obj_t *obj, lv_flex_align_t main_place, lv_flex_align_t cross_place, lv_flex_align_t track_cross_place)¶ Set how to place (where to align) the items and tracks
- Parameters
flex -- pointer: to a flex layout descriptor
main_place -- where to place the items on main axis (in their track). Any value of
lv_flex_align_t.cross_place -- where to place the item in their track on the cross axis.
LV_FLEX_ALIGN_START/END/CENTERtrack_place -- where to place the tracks in the cross direction. Any value of
lv_flex_align_t.
-
void
lv_obj_set_flex_grow(lv_obj_t *obj, uint8_t grow)¶ Sets the width or height (on main axis) to grow the object in order fill the free space
- Parameters
obj -- pointer to an object. The parent must have flex layout else nothing will happen.
grow -- a value to set how much free space to take proportionally to other growing items.
-
void
lv_style_set_flex_flow(lv_style_t *style, lv_flex_flow_t value)¶
-
void
lv_style_set_flex_main_place(lv_style_t *style, lv_flex_align_t value)¶
-
void
lv_style_set_flex_cross_place(lv_style_t *style, lv_flex_align_t value)¶
-
void
lv_style_set_flex_track_place(lv_style_t *style, lv_flex_align_t value)¶
-
void
lv_style_set_flex_grow(lv_style_t *style, uint8_t value)¶
-
void
lv_obj_set_style_flex_flow(lv_obj_t *obj, lv_flex_flow_t value, lv_style_selector_t selector)¶
-
void
lv_obj_set_style_flex_main_place(lv_obj_t *obj, lv_flex_align_t value, lv_style_selector_t selector)¶
-
void
lv_obj_set_style_flex_cross_place(lv_obj_t *obj, lv_flex_align_t value, lv_style_selector_t selector)¶
-
void
lv_obj_set_style_flex_track_place(lv_obj_t *obj, lv_flex_align_t value, lv_style_selector_t selector)¶
-
static inline lv_flex_flow_t
lv_obj_get_style_flex_flow(const lv_obj_t *obj, uint32_t part)¶
-
static inline lv_flex_align_t
lv_obj_get_style_flex_main_place(const lv_obj_t *obj, uint32_t part)¶
-
static inline lv_flex_align_t
lv_obj_get_style_flex_cross_place(const lv_obj_t *obj, uint32_t part)¶
-
static inline lv_flex_align_t
lv_obj_get_style_flex_track_place(const lv_obj_t *obj, uint32_t part)¶
Variables
-
uint16_t
LV_LAYOUT_FLEX¶
-
lv_style_prop_t
LV_STYLE_FLEX_FLOW¶
-
lv_style_prop_t
LV_STYLE_FLEX_MAIN_PLACE¶
-
lv_style_prop_t
LV_STYLE_FLEX_CROSS_PLACE¶
-
lv_style_prop_t
LV_STYLE_FLEX_TRACK_PLACE¶
-
lv_style_prop_t
LV_STYLE_FLEX_GROW¶