行业资讯
📅 2026/8/11 2:18:04
LVGL学习笔记(四)
LVGL学习笔记四属性与布局前言在前一篇学习笔记中我们成功创建了一个标签部件并且在画面上显示hello world但是在工程中一个界面常常不只有单个部件对象而是多个不同功能的部件对象组合在一起的。在这种情况下我们就必须考虑部件的摆放和部件与部件之间大小设置和页面布局了。这一篇我们围绕按键部件的属性、多个按键之间的布局来阐述相关概念。最后创建一个简易底部按钮工具栏的项目界面来演示功能的实现。什么是对象的属性**属性用来修饰控件尺寸、位置、外观、交互的。**在之间的笔记中我们对象将对象比作一个“积木块”一个实实在在的控件那么属性就是这个“积木块”的大小、颜色、形状等具体信息。具体来说对象一个实实在在的部件按钮、标签、容器、滑块。属性用来描述这个对象长什么样、位置、大小、颜色、开关状态、文本、透明度的各项特征参数。可以将属性分为如下几类基本属性LVGL在设计的时候参考了CSS的盒子模型相关概念所谓盒子模型就是每一个 LVGL 控件 (对象) 就是一个方块盒子如下图所示盒子由内往外一共四层分别是1.内容存放真正东西按钮文字、图片、标签文字。宽高默认就是内容区域的尺寸。2.内边距内容和自己边框之间的留白。3.边框盒子的边线、圆角边框。边框会占盒子的空间厚度。4.外边距当前盒子 和 旁边别的控件之间的间隔。基本属性包括对象的位置尺寸属性例如对象的位置、大小、对齐方式、内外边距、布局方式等。由于部件有多种实现方式故属性的函数也有许多这里不做一一列举感兴趣的可以参考LGVL提供的官方手册这里只介绍作者习惯使用的。下面主要分析一下基本属性用到的函数如下表所示函数描述lv_obj_set_pos(对象指针,x坐标,y坐标)设置左上角坐标位置lv_obj_set_size(对象指针, 高度, 宽度);设置对象尺寸大小lv_obj_align对象指针对齐模式x轴偏移量y轴偏移量.设置对齐方式lv_pct(value)将一个值转换为百分比lv_obj_set_style_pad_all对象指针内边距值应用式样设置对象所有内边距lv_style_set_border_width(对象指针, 宽度);设置边框宽度lv_style_set_border_color对象指针, 颜色设置边框颜色lv_style_set_border_opa对象指针透明度设置边框透明度lv_style_set_radius对象指针圆角半径设置边框圆角样式属性样式属性是一个大的分类其中又可以分为大小位置属性、填充属性、背景属性、边框属性、轮廓属性、阴影属性、图片属性、线条属性、圆弧属性和文本属性等等。式样属性的其中一个特点就是lv_obj_set_style_xxx本地样式或者 lv_style_set_xxx 普通样式的格式因此我们在设置某个样式的时候只需要记住关键的单词即可例如宽度width设置的函数为lv_obj_set_style_width。上述基本属性中边框对象部分也可以归类到式样属性中来由于式样属性用到的函数太多只能在之后的笔记中用到时再进行介绍。这里据几个常用的进行介绍函数描述lv_obj_set_style_text_font对象指针字体大小状态设置字体大小lv_obj_set_style_text_color对象指针字体大小状态设置文本颜色lv_obj_add_state(对象指针, 状态);设置组件的状态lv_obj_clear_statee对象指针, 状态清除组件的状态式样的特点1.复用与级联: 一个样式可以被多个对象使用。2.继承: 如果对象没有指定某个属性如文本颜色它会从父对象继承。3.本地样式: 对象可以拥有高优先级的“本地样式”用于进行个别的、独特的样式设置。4.过渡效果: 样式支持过渡动画可以在状态改变时产生平滑的视觉效果。滚动属性在 LVGL 中任何对象都是支持滚动的。如果一个对象在其父对象的区域之外则该父 对象将变为可滚动的并且在其内部出现滚动条。滚动属性的相关介绍需要等理解了事件的相关概念后才方便演示这里不过多表述。动画属性优秀的过渡动画可以让用户的 GUI 变得更具高级感。在 LVGL 中用户可指定动画的开 始值和结束值该动画将通过回调函数来处理。动画属性的相关介绍需要等理解了定时器的相关概念后才方便演示这里同样不过多表述。其他属性由于状态和事件概念还没有阐述所以先将状态属性和事件属性归到其他属性中。除此之外由于LVGL还在不断地更新版本V9中出现许多新的属性类型无法用上述的属性进行归类就将其归如其他属性中。LVGL 核心对象属性分为几种有什么区别具体在项目中如何使用属性可以分为两种分别是对象直接属性和初始化属性。其区别是对象直接属性可以调用函数lv_obj_xxx直接修改。而初始化属性需要先初始化样式再挂载到部件中去。项目当中通用使用步骤创建父容器设置大小、对齐、开启布局等初始化公共样式配置盒子模型、圆角、间距等创建子控件设置尺寸给控件挂载常态 / 按压样式设置可见性、启用状态、点击回调一般项目都存在前两步骤后面的步骤根据项目实际情况灵活增减。LVGL 布局方式有哪几种分别有什么区别具体的使用场景是什么布局本质就是管控子控件位置、大小。布局可以分为默认布局、Flex弹性布局和Grid网格布局三种下面分别进行介绍1.默认布局LVGL 的布局设计深受 CSS 启发其主要内容涉及 3 个方面坐标位置、大小以及对齐方式。如果在创建控件时不给控件安排布局那么控件默认会被放在父容器的左上角。可以使用 lv_obj_set_pos(obj, 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中间对齐外部对齐对齐模式描述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_MID在外左边中间对齐LV_ALIGN_OUT _RIGHT_MID在外右边中间对齐对齐方式如下图所示从图片中可以看到控件之间不仅可以内对齐也可以外对齐。如果两个控件间没有包含关系也不要紧可以使用 lv_obj_align_to(obj, base, align, x_ofs, y_ofs); 设置两个控件的相对对齐方式。默认布局这种布局方式非常死板因为绝对坐标一旦设定就不能自动调整,而且当控件数量较多时也很难确定合适的坐标值但对于控件较少的场景默认布局已经可以满足需求了。2.Flex弹性布局Flex 布局是一种可以简便、完整、响应式地实现各种页面布局它是 CSS 的一个重点应用。启用 Flex 布局在 lv_conf.h 文件中把 LV_USE_FLEX 配置项置 1 即可启用 Flex 布局。/*A layout similar to Flexbox in CSS.*/#define LV_USE_FLEX1flex布局配置项轨道行或列。主轴行或列对象放置的方向。交叉轴垂直于主轴。换行/换列如果轨道中没有更多空间则开始新轨道增长如果设置在一个项目上它将增长以填充轨道上的剩余空间。间隙行和列或轨道上的对象之间的空间。flex布局相关函数在LVGL中所有与 Flex 相关的值都是底层的样式属性这些与 Flex 相关的样式属性函数 如下表所示函数描述lv_style_set_flex_flow()设置 Flex 流动布局lv_style_set_flex_main_place()设置主轴lv_style_set_flex_cross_place()设置交叉轴lv_style_set_flex_track_place()设置轨道轴lv_style_set_flex_grow()设置增长下面挨个介绍对应函数设置 Flex 流动布局如果不添加任何布局方式那么所有的控件都会堆放在左上角。flex 布局可以将一些控件按行或列均匀布局并且可以自动调整它们的间距。可以给一个容器设置一个 flex-flow 属性这样容器就可以使用 flex 布局方式voidlv_obj_set_flex_flow(lv_obj_t*obj,lv_flex_flow_tflow);参数说明形参说明obj指向设置Flex布局的对象flowflex 布局方式该函数无返回值。flow形参的转入值下表所示配置项描述LV_FLEX_FLOW_ROW将子类们排成一行并不换行LV_FLEX_FLOW_ROW_WRAP将子类们排成一行并换行LV_FLEX_FLOW_ROW_REVERSE将子类们排成一行并不换行且顺序相反LV_FLEX_FLOW_ROW_WRAP_REVERSE将子类们排成一行并换行且顺序相反LV_FLEX_FLOW_COLUMN将子类们排成一列并不换行LV_FLEX_FLOW_COLUMN_WRAP将子类们排成一列并换行LV_FLEX_FLOW_COLUMN_REVERSE将子类们排成一列并不换行且顺序相反LV_FLEX_FLOW_COLUMN_WRAP_REVERSE将子类们排成一列并换行且顺序相反flex布局的对齐以上 flex 布局中各控件的尺寸和间距都是固定的并且第一个控件依然会出现在左上角。如果可以使用**lv_obj_set_flex_align**函数进行修改。voidlv_obj_set_flex_align(lv_obj_t*obj,lv_flex_align_tmain_place,lv_flex_align_tcross_place,lv_flex_align_ttrack_place)参数说明形参说明obj指向设置对齐的对象main_place主轴上的对象对齐cross_place交叉轴上的对象对齐track_place行/列交叉轴上的对象对齐该函数无返回值。main_place、cross_place 和 track_cross_place 形参的转入值如下表所示配置项描述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 形参flex布局弹性增长简单来说flex 弹性增长 (flex_grow)当父容器还有剩余空余空间的时候规定子控件瓜分剩下空位的权重。例如父容器宽度 300px里面并排 3 个按钮按钮基础宽度各 60px。那么总占用为60×3 180px剩余空闲空间 300-180 120px得到flex‑grow 就是决定这 120 多余空间怎么分给各个子按钮。具体函数原型如下voidlv_obj_set_flex_grow(lv_obj_t*obj,uint8_tgrow)函数形参说明如下形参说明obj需要设置的子对象grow大于 0 表示可扩展值越大分配的剩余空间越多0 表示不扩展。3.Grid网格布局flexbox是 一种一维的布局是因为一个 flexbox 一次只能处理一个维度上的元素布局一行或者一列 但是 Grid 布局是一种二维布局它可以同时处理行和列上的布局。要使用网格布局需要在配置文件 lv_conf.h 中启用 LV_USE_GRID 宏定义否则使用弹性布局相关的内容将提示未定义的类型。/*A layout similar to Grid in CSS.*/#define LV_USE_GRID1Grid布局配置项轨道(tracks)行或列。空闲单元(FR)如果在轨道上设置了大小FR 它将增长以填充父级的剩余空间。间隙(gap)行和列或轨道上的项目之间的空间。Grid布局相关函数在LVGL中所有与 Grid 相关的值都是底层的样式属性这些与 Grid 相关的样式属性函数如下所示函数描述lv_obj_set_style_grid_column_dsc_array()绑定列配置lv_obj_set_style_grid_row_dsc_array()绑定行配置lv_obj_set_layout()启用 Grid 布局lv_obj_set_grid_cell()设置弹簧拉伸lv_obj_set_grid_align()设置Grid 布局对齐方式网格描述符使用 Grid 布局的第一步是通过数组定义网格的行高和列宽数组最后一个元素必须为 LV_GRID_TEMPLATE_LAST。示例代码如下// 定义列描述2列宽度分别为100px、400pxstaticint32_tcolumn_dsc[]{100,400,LV_GRID_TEMPLATE_LAST};// 定义行描述3行每行高度100pxstaticint32_trow_dsc[]{100,100,100,LV_GRID_TEMPLATE_LAST};使用 Grid 布局的第二步就是绑定行和列数组示例代码如下// 设置对象网格布局行描述数组lv_obj_set_style_grid_column_dsc_array(cont,col_dsc,0);// 设置对象网格布局列描述数组lv_obj_set_style_grid_row_dsc_array(cont,row_dsc,0);最后启动Grid 布局。LVGL 内置了几种简单布局可通过函数lv_obj_set_layout快速启用示例代码如下lv_obj_set_layout(btn,LV_LAYOUT_GRID);网格布局对齐方式通过核心函数设置子控件在网格中的位置、对齐方式和占用空间。Grid 对齐与 flex 容器对齐标准是类似的需要注意的是Grid 对齐使用的是 lv_obj_set_grid_align函数并不是 lv_obj_set_flex_align函数。对应函数原型如下voidlv_obj_set_grid_align(lv_obj_t*obj,lv_grid_align_tcolumn_align,lv_grid_align_trow_align)对应形参如下形参说明obj指向要对齐的对象column_align行对齐row_align列对齐常用对齐规则有如下几种分别是LV_GRID_ALIGN_START左 / 上对齐默认LV_GRID_ALIGN_END右 / 下对齐LV_GRID_ALIGN_CENTER居中摆放LV_GRID_ALIGN_SPACE_EVENLY所有间距均等LV_GRID_ALIGN_SPACE_AROUND控件两侧间距相等LV_GRID_ALIGN_SPACE_BETWEEN两端对齐中间均分该函数无返回值网格布局的弹簧拉伸对应函数原型如下// 函数参数说明lv_obj_set_grid_cell(child,// 要摆放的子控件col_align,// 水平对齐方式col_pos,// 列索引从0开始col_span,// 占用列数row_align,// 垂直对齐方式row_pos,// 行索引从0开始row_span// 占用行数);column_align和 row_align 确定如何在其单元格中对齐子项。 可能的值为LV_GRID_ALIGN_START 表示在水平方向和垂直方向的顶部左侧。 默认LV_GRID_ALIGN_END 表示水平和底部垂直LV_GRID_ALIGN_CENTER 只是居中colum_pos 和 row_pos 表示应该放置项目中单元格的从零开始的索引。colum_span 和 row_span 表示该项目应该从起始单元格开始包含多少个轨道。 必须 1.综上所述三种布局各自适合的使用场景如下布局适用场景NONE自由拖拽、少量控件Flex菜单栏、列表、横向按钮组、状态栏Grid数字键盘、设置九宫格、表格 UI接下来举上述的例子使用flex布局设置一个一个简易底部按钮工具栏的界面参考代码如下// 封装创建按钮函数lv_obj_t*create_btn(lv_obj_t*parent,constchar*txt){lv_obj_t*btnlv_btn_create(parent);lv_obj_set_flex_grow(btn,1);lv_obj_set_style_pad_all(btn,8,0);lv_obj_t*labellv_label_create(btn);lv_label_set_text(label,txt);lv_obj_center(label);//移除多余括号returnbtn;}voidlv_mainstart(void){// 1. 创建底层容器底部工具栏lv_obj_t*barlv_obj_create(lv_scr_act());// 设置容器尺寸铺满屏幕宽度、高度80pxlv_obj_set_size(bar,LV_PCT(100),80);// 对齐到屏幕底部lv_obj_align(bar,LV_ALIGN_BOTTOM_MID,0,0);// 设置内边距lv_obj_set_style_pad_all(bar,10,0);// 开启横向Flex布局lv_obj_set_layout(bar,LV_LAYOUT_FLEX);lv_obj_set_flex_flow(bar,LV_FLEX_FLOW_ROW);// 子控件之间均分剩余空间lv_obj_set_flex_align(bar,LV_FLEX_ALIGN_SPACE_EVENLY,LV_FLEX_ALIGN_CENTER,LV_FLEX_ALIGN_CENTER);// 创建3个功能按键create_btn(bar,home);create_btn(bar,setting);create_btn(bar,about);}演示结果