一、前言
这节总结一下整体页面的布局方式,lvgl的布局方式比较少,目前只有flex和grid两大类布局,即弹性布局和网格布局,弹性布局一般就是指定相对位置,网格布局就是将整个页面划分为网格状,我们做其它的UI开发虽然可能有更多的方式,但是基本这两类的布局方式已经足够灵活,满足我们的页面布局要求。
二、布局示例
1、flex弹性布局示例1(纵向和横向布局)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES/*** 使用 Flexbox 的简单行列布局*/
void lv_example_flex_1(void)
{/*创建具有 ROW flex 方向的容器*/lv_obj_t * cont_row = lv_obj_create(lv_screen_active());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);/*创建具有 COLUMN flex方向的容器*/lv_obj_t * cont_col = lv_obj_create(lv_screen_active());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_button_create(cont_row);lv_obj_set_size(obj, 100, LV_PCT(100));label = lv_label_create(obj);lv_label_set_text_fmt(label, "Item: %"LV_PRIu32"", i);lv_obj_center(label);/*Add items to the column*/obj = lv_button_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
展示:带有横向弹性布局容器以及纵向弹性布局的容器,然后向其中添加label等内容即可。
2、flex弹性布局示例2(wrap布局自动化换行)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES/*** 用包裹将物品排成行,并放置物品以使其周围有均匀的空间。*/
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_screen_active());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
展示:用wrap将items排成行,并放置物品以使其周围有均匀的空间。
3、flex弹性布局示例3(弹性增长)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES/*** 展示弹性增长。*/
void lv_example_flex_3(void)
{lv_obj_t * cont = lv_obj_create(lv_screen_active());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); /*固定尺寸*/obj = lv_obj_create(cont);lv_obj_set_height(obj, 40);lv_obj_set_flex_grow(obj, 1); /*可用空间的 1 部分*/obj = lv_obj_create(cont);lv_obj_set_height(obj, 40);lv_obj_set_flex_grow(obj, 2); /*自由空间的 2 部分*/obj = lv_obj_create(cont);lv_obj_set_size(obj, 40, 40); /*固定尺寸。它被“生长”项目冲到右侧*/
}#endif
展示:弹性增长
4、flex弹性布局示例4(反转弹性项目的顺序)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES/*** 反转弹性项目的顺序*/
void lv_example_flex_4(void)
{lv_obj_t * cont = lv_obj_create(lv_screen_active());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
展示:反转弹性项目的顺序
5、flex弹性布局示例5(布局行和列添加样式属性)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLESstatic 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);
}/*** 演示列和行间隙样式属性的效果*/
void lv_example_flex_5(void)
{lv_obj_t * cont = lv_obj_create(lv_screen_active());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_duration(&a, 500);lv_anim_set_playback_duration(&a, 500);lv_anim_start(&a);lv_anim_set_exec_cb(&a, column_gap_anim);lv_anim_set_duration(&a, 3000);lv_anim_set_playback_duration(&a, 3000);lv_anim_start(&a);
}#endif
展示:列和行间隙样式属性的效果。
6、flex弹性布局示例6(RTL从右到左布局)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES/*** RTL 基本方向更改项目的顺序。* 还演示水平滚动如何与 RTL 配合使用。*/
void lv_example_flex_6(void)
{lv_obj_t * cont = lv_obj_create(lv_screen_active());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从右到左的布局方式,以及水平滚动和RTL配合。
7、grid网格布局示例1(基本的网格布局)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES/*** 一个简单的网格*/
void lv_example_grid_1(void)
{static int32_t col_dsc[] = {70, 70, 70, LV_GRID_TEMPLATE_LAST};static int32_t row_dsc[] = {50, 50, 50, LV_GRID_TEMPLATE_LAST};/*创建一个带有网格的容器*/lv_obj_t * cont = lv_obj_create(lv_screen_active());lv_obj_set_style_grid_column_dsc_array(cont, col_dsc, 0);lv_obj_set_style_grid_row_dsc_array(cont, row_dsc, 0);lv_obj_set_size(cont, 300, 220);lv_obj_center(cont);lv_obj_set_layout(cont, LV_LAYOUT_GRID);lv_obj_t * label;lv_obj_t * obj;uint32_t i;for(i = 0; i < 9; i++) {uint8_t col = i % 3;uint8_t row = i / 3;obj = lv_button_create(cont);/*水平和垂直拉伸单元格 将跨度设置为 1 以使单元格为 1 列/行大小*/lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,LV_GRID_ALIGN_STRETCH, row, 1);label = lv_label_create(obj);lv_label_set_text_fmt(label, "c%d, r%d", col, row);lv_obj_center(label);}
}#endif
展示:基本的网格布局。
8、grid网格布局示例2(单元布局和span跨度)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES/*** 展示单元布局和跨度*/
void lv_example_grid_2(void)
{static int32_t col_dsc[] = {70, 70, 70, LV_GRID_TEMPLATE_LAST};static int32_t row_dsc[] = {50, 50, 50, LV_GRID_TEMPLATE_LAST};/*创建一个带有网格的容器*/lv_obj_t * cont = lv_obj_create(lv_screen_active());lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc);lv_obj_set_size(cont, 300, 220);lv_obj_center(cont);lv_obj_t * label;lv_obj_t * obj;/*单元格设置为 0;0 并水平和垂直对齐到开头(左/上)*/obj = lv_obj_create(cont);lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 0, 1,LV_GRID_ALIGN_START, 0, 1);label = lv_label_create(obj);lv_label_set_text(label, "c0, r0");/*单元格设置为 1;0 并水平对齐到起始位置(左侧)并垂直居中*/obj = lv_obj_create(cont);lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 1, 1,LV_GRID_ALIGN_CENTER, 0, 1);label = lv_label_create(obj);lv_label_set_text(label, "c1, r0");/*C将单元格设置为 2;0 并水平对齐到起点(左侧),垂直对齐到终点(底部)*/obj = lv_obj_create(cont);lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 2, 1,LV_GRID_ALIGN_END, 0, 1);label = lv_label_create(obj);lv_label_set_text(label, "c2, r0");/*单元格为 1;1 但 2 列宽(跨度 = 2)。将宽度和高度设置为拉伸。*/obj = lv_obj_create(cont);lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 1, 2,LV_GRID_ALIGN_STRETCH, 1, 1);label = lv_label_create(obj);lv_label_set_text(label, "c1-2, r1");/*单元格为 0;1,但有 2 行高(跨度 = 2)。将宽度和高度设置为拉伸。*/obj = lv_obj_create(cont);lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 0, 1,LV_GRID_ALIGN_STRETCH, 1, 2);label = lv_label_create(obj);lv_label_set_text(label, "c0\nr1-2");
}#endif
展示:单元布局和span跨度。
9、grid网格布局示例3(网格自由单元)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES/*** 展示网格的“自由单元”*/
void lv_example_grid_3(void)
{/*Column 1: fix width 60 px*Column 2: 1 unit from the remaining free space*Column 3: 2 unit from the remaining free space*/static int32_t col_dsc[] = {60, LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST};/*Row 1: fix width 50 px*Row 2: 1 unit from the remaining free space*Row 3: fix width 50 px*/static int32_t row_dsc[] = {50, LV_GRID_FR(1), 50, LV_GRID_TEMPLATE_LAST};/*创建一个带有网格的容器*/lv_obj_t * cont = lv_obj_create(lv_screen_active());lv_obj_set_size(cont, 300, 220);lv_obj_center(cont);lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc);lv_obj_t * label;lv_obj_t * obj;uint32_t i;for(i = 0; i < 9; i++) {uint8_t col = i % 3;uint8_t row = i / 3;obj = lv_obj_create(cont);/*水平和垂直拉伸单元格 将跨度设置为 1 以使单元格为 1 列/行大小*/lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,LV_GRID_ALIGN_STRETCH, row, 1);label = lv_label_create(obj);lv_label_set_text_fmt(label, "%d,%d", col, row);lv_obj_center(label);}
}#endif
展示:网格的自由单元。
10、grid网格布局示例4(轨道放置)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES/*** 演示轨道放置*/
void lv_example_grid_4(void)
{static int32_t col_dsc[] = {60, 60, 60, LV_GRID_TEMPLATE_LAST};static int32_t row_dsc[] = {45, 45, 45, LV_GRID_TEMPLATE_LAST};/*在列之间添加空间并将行移至底部(末尾)*//*创建一个带有网格的容器*/lv_obj_t * cont = lv_obj_create(lv_screen_active());lv_obj_set_grid_align(cont, LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_END);lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc);lv_obj_set_size(cont, 300, 220);lv_obj_center(cont);lv_obj_t * label;lv_obj_t * obj;uint32_t i;for(i = 0; i < 9; i++) {uint8_t col = i % 3;uint8_t row = i / 3;obj = lv_obj_create(cont);/*水平和垂直拉伸单元格 将跨度设置为 1 以使单元格为 1 列/行大小*/lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,LV_GRID_ALIGN_STRETCH, row, 1);label = lv_label_create(obj);lv_label_set_text_fmt(label, "%d,%d", col, row);lv_obj_center(label);}
}#endif
展示:轨道放置。
11、grid网格布局示例5(列和行间隙)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLESstatic 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);
}/*** 展示列和行间隙*/
void lv_example_grid_5(void)
{/*60x60 cells*/static int32_t col_dsc[] = {60, 60, 60, LV_GRID_TEMPLATE_LAST};static int32_t row_dsc[] = {45, 45, 45, LV_GRID_TEMPLATE_LAST};/*创建一个带有网格的容器*/lv_obj_t * cont = lv_obj_create(lv_screen_active());lv_obj_set_size(cont, 300, 220);lv_obj_center(cont);lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc);lv_obj_t * label;lv_obj_t * obj;uint32_t i;for(i = 0; i < 9; i++) {uint8_t col = i % 3;uint8_t row = i / 3;obj = lv_obj_create(cont);lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,LV_GRID_ALIGN_STRETCH, row, 1);label = lv_label_create(obj);lv_label_set_text_fmt(label, "%d,%d", col, row);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_duration(&a, 500);lv_anim_set_playback_duration(&a, 500);lv_anim_start(&a);lv_anim_set_exec_cb(&a, column_gap_anim);lv_anim_set_duration(&a, 3000);lv_anim_set_playback_duration(&a, 3000);lv_anim_start(&a);
}#endif
展示:列和行间隙。
12、grid网格布局示例6(RTL方向)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES/*** 在网格上演示 RTL 方向*/
void lv_example_grid_6(void)
{static int32_t col_dsc[] = {60, 60, 60, LV_GRID_TEMPLATE_LAST};static int32_t row_dsc[] = {45, 45, 45, LV_GRID_TEMPLATE_LAST};/*创建一个带有网格的容器*/lv_obj_t * cont = lv_obj_create(lv_screen_active());lv_obj_set_size(cont, 300, 220);lv_obj_center(cont);lv_obj_set_style_base_dir(cont, LV_BASE_DIR_RTL, 0);lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc);lv_obj_t * label;lv_obj_t * obj;uint32_t i;for(i = 0; i < 9; i++) {uint8_t col = i % 3;uint8_t row = i / 3;obj = lv_obj_create(cont);/*水平和垂直拉伸单元格 将跨度设置为 1 以使单元格为 1 列/行大小*/lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,LV_GRID_ALIGN_STRETCH, row, 1);label = lv_label_create(obj);lv_label_set_text_fmt(label, "%d,%d", col, row);lv_obj_center(label);}
}#endif
展示:RTL方向。
三、最后
基本上布局就这些了,我们设计的页面也都根据网格或者弹性布局做组合和划分。