4. LVGL核心概念
从 TouchGFX 迁移到 LVGL,最大的认知转变不是 API 名称的变化,而是对象模型的变化。TouchGFX 以 Screen 和 View 为组织中心,控件通常直接挂在 Screen 下;LVGL 则采用统一的 lv_obj_t 对象树,屏幕、容器、按钮、标签、图表全部是对象,父子关系决定坐标、可见性、裁剪和事件传播。理解这六个核心概念,迁移工作才能从“逐行翻译”升级为“结构重构”。
一、对象树:一切皆对象的父子结构
LVGL 中每个可视元素都是 lv_obj_t 实例,通过 lv_obj_create(parent) 创建时即确定父对象。子对象坐标默认相对于父对象内容区,父对象移动、隐藏或删除时,子对象随之联动。屏幕是最顶层对象,可用 lv_scr_act() 获取当前活动屏幕,用 lv_layer_top() 和 lv_layer_sys() 获取顶层与系统层。
lv_obj_t *scr = lv_scr_act();
lv_obj_t *card = lv_obj_create(scr); // 卡片容器
lv_obj_t *label = lv_label_create(card); // 标签挂在卡片下
lv_label_set_text(label, "Temperature");
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 12, 8);
对象树还决定事件冒泡方向:子对象未处理的事件会向父对象传递,这为统一处理点击、长按提供了便利。迁移时,TouchGFX 中通过 add() 加入 View 的控件,应重新评估其父容器,避免全部平铺到屏幕导致布局难以维护。
二、控件体系:基础对象与专用部件
LVGL 控件分为两类:一类是基础对象 lv_obj,可作容器、面板、分隔线;另一类是专用部件,如 lv_btn、lv_label、lv_slider、lv_switch、lv_chart、lv_table、lv_img、lv_arc 等。专用部件由基础对象加样式和事件逻辑构成,因此它们同样支持父子嵌套、布局和动画。
与 TouchGFX 的 Widget 相比,LVGL 控件更强调“组合”:例如一个带图标的按钮,通常由按钮容器加标签或图片子对象组成,而不是依赖单一控件内置图标属性。迁移时应先建立控件映射表,再决定哪些 TouchGFX 自定义控件需要拆解为 LVGL 组合对象。
三、样式与主题:状态化、可复用的外观系统
LVGL 样式 lv_style_t 是独立于对象的属性集合,可被多个对象共享。样式按“部件 + 状态”生效,例如按钮的 LV_PART_MAIN 在 LV_STATE_PRESSED 下可使用不同背景色。主题则是全局样式集合,lv_theme_default_init() 可设置主色、暗色模式和字体。
static lv_style_t style_card;
lv_style_init(&style_card);
lv_style_set_bg_color(&style_card, lv_color_hex(0xFFFFFF));
lv_style_set_radius(&style_card, 12);
lv_style_set_pad_all(&style_card, 16);
lv_obj_add_style(card, &style_card, LV_PART_MAIN);
四、事件回调、动画、布局与滚动机制
事件回调通过 lv_obj_add_event_cb() 注册,回调函数签名统一为 void (*)(lv_event_t *),常用事件包括 LV_EVENT_CLICKED、LV_EVENT_VALUE_CHANGED、LV_EVENT_PRESSED、LV_EVENT_READY。与 TouchGFX 的虚函数重写不同,LVGL 用回调注册实现解耦,一个对象可注册多个回调。
动画使用 lv_anim_t 描述起止值、时间、路径和回调,可作用于坐标、透明度、缩放、旋转等属性。布局方面,LVGL 提供 Flex 和 Grid 两种布局,通过 lv_obj_set_flex_flow() 或 lv_obj_set_grid_dsc_array() 启用,子对象可自动排列,减少手工计算坐标。滚动则由 lv_obj_set_scroll_dir()、lv_obj_set_scrollbar_mode() 控制,容器内容超出时自动出现滚动条。
五、迁移中的典型误区与复盘
| 误区 | 表现 | 修正方式 |
|---|---|---|
| 把所有控件平铺到屏幕 | 坐标硬编码,分辨率变化后错位 | 用容器 + Flex/Grid 重新组织父子层级 |
| 逐控件设置颜色字体 | 代码冗长,换肤困难 | 抽取 lv_style_t,按状态复用 |
| 用轮询代替事件 | CPU 占用高,响应不及时 | 改用 lv_obj_add_event_cb 注册回调 |
| 忽略滚动容器 | 内容溢出被裁剪,用户无法查看 | 设置滚动方向与滚动条模式 |
| 动画直接改坐标 | 与布局冲突,画面抖动 | 用 lv_anim 作用于样式属性或独立层 |
掌握对象树、控件体系、样式主题、事件回调、动画、布局与滚动这六个概念后,LVGL 的代码组织方式会变得清晰:对象树负责结构,样式负责外观,事件负责交互,动画负责过渡,布局与滚动负责空间管理。迁移不再是 API 替换,而是一次界面架构的重新梳理。