4. LVGL布局管理
任务目标
在ESP32上使用LVGL的Flexbox与Grid布局,创建一组自适应排列的控件。当屏幕尺寸或容器大小变化时,控件能够自动调整位置与间距,无需手动计算坐标。
环境依赖
本案例基于LVGL v8.x,需要确保lv_conf.h中已启用Flex和Grid布局:
#define LV_USE_FLEX 1
#define LV_USE_GRID 1
核心实现
以下代码创建两个容器:左侧使用Flexbox实现按钮流式换行排列,右侧使用Grid实现3×2的均匀网格控件。两个容器均设置为LV_SIZE_CONTENT高度,随内容自适应。
#include <lvgl.h>
void layout_demo_create(lv_obj_t *parent) {
// 父容器:水平排列两个子容器
lv_obj_t *root = lv_obj_create(parent);
lv_obj_set_size(root, lv_pct(100), lv_pct(100));
lv_obj_set_flex_flow(root, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(root, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_all(root, 10, 0);
/* ---------- 左侧:Flexbox 流式排列 ---------- */
lv_obj_t *flex_box = lv_obj_create(root);
lv_obj_set_size(flex_box, lv_pct(45), LV_SIZE_CONTENT);
lv_obj_set_flex_flow(flex_box, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_flex_align(flex_box, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_all(flex_box, 8, 0);
lv_obj_set_style_border_width(flex_box, 1, 0);
// 添加7个不同宽度的按钮,验证自动换行
const char *labels[] = {"A", "BC", "DEF", "G", "HIJK", "LM", "NOPQ"};
for (int i = 0; i < 7; i++) {
lv_obj_t *btn = lv_btn_create(flex_box);
lv_obj_set_size(btn, LV_SIZE_CONTENT, 36);
lv_obj_t *lbl = lv_label_create(btn);
lv_label_set_text(lbl, labels[i]);
lv_obj_center(lbl);
}
/* ---------- 右侧:Grid 3x2 均匀网格 ---------- */
lv_obj_t *grid_box = lv_obj_create(root);
lv_obj_set_size(grid_box, lv_pct(45), LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(grid_box, 8, 0);
lv_obj_set_style_border_width(grid_box, 1, 0);
// 定义列宽:3列等分,行高固定40px
static lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_END};
static lv_coord_t row_dsc[] = {40, 40, LV_GRID_TEMPLATE_END};
lv_obj_set_grid_dsc_array(grid_box, col_dsc, row_dsc);
// 添加6个色块控件
static lv_color_t colors[] = {LV_COLOR_MAKE(255, 80, 80), LV_COLOR_MAKE(80, 255, 80),
LV_COLOR_MAKE(80, 80, 255), LV_COLOR_MAKE(255, 200, 0),
LV_COLOR_MAKE(200, 0, 255), LV_COLOR_MAKE(0, 200, 255)};
for (int i = 0; i < 6; i++) {
lv_obj_t *cell = lv_obj_create(grid_box);
lv_obj_set_style_bg_color(cell, colors[i], 0);
lv_obj_set_style_border_width(cell, 0, 0);
lv_obj_set_style_radius(cell, 4, 0);
lv_obj_set_grid_cell(cell, LV_GRID_ALIGN_STRETCH, i % 3, 1,
LV_GRID_ALIGN_STRETCH, i / 3, 1);
}
}
/* 调用示例:在UI初始化时执行 */
void ui_init(void) {
lv_obj_t *scr = lv_scr_act();
layout_demo_create(scr);
}
运行与验证
- 将代码复制到ESP32项目中,确保LVGL已初始化且显示驱动正常。
- 编译烧录后,观察屏幕:左侧按钮在容器宽度不足时自动换行,右侧6个色块均匀分布在3列2行的网格中。
- 修改
root容器的lv_pct(100)为lv_pct(80)或调整屏幕分辨率,重新编译运行,确认两组控件仍保持自适应排列,无重叠或溢出。
通过条件:屏幕旋转或容器尺寸变化后,Flex容器内按钮自动重排且不超出边界;Grid容器内色块始终等宽等高填满网格单元,间距均匀。
关键说明:Flex布局中LV_FLEX_FLOW_ROW_WRAP允许子项在空间不足时换行;Grid布局通过LV_GRID_FR(1)实现等分列宽,LV_GRID_ALIGN_STRETCH使控件自动填满单元格。两个容器均使用LV_SIZE_CONTENT高度,使其高度由内容撑开,便于嵌入不同尺寸的父容器。