这次我们来看 LVGL 模拟手机效果。核心不是把 Android 或 iOS 装到开发板上,而是用 LVGL 这个嵌入式图形库,在 PC 模拟器或者 MCU 上做出类似手机的 UI 交互:状态栏、主屏应用图标、左右滑屏、页面转场、通知面板、开关控件、滑动动画。它的意义在于,UI 设计和底层驱动可以先用模拟器跑通,再移植到 STM32、ESP32 这类资源受限的硬件上,手机效果只是验证工具链和控件能力的一种高密度场景。
这个题目最值得关注的是三件事:第一,LVGL 自带 PC 模拟器,不需要真实屏幕和触摸屏就能用鼠标模拟触摸;第二,动画、布局、样式系统足够做出“类手机”的交互效果,控件覆盖按钮、标签、开关、滑块、键盘、列表、图表等常见元素;第三,它从设计到上板有一套完整工作流,包括可视化 UI 编辑器、字库生成工具、内存调优手段。本文会带你完成模拟器搭建、主屏应用网格、状态栏、左右滑屏、开关事件、动画、内存与帧率监控、常见坑排查,以及最终怎么落到 STM32 / ESP32 工程里。
适合的读者是:刚接触 LVGL 的嵌入式新人、想在项目里用 LVGL 做 GUI 的硬件工程师、以及需要在真实设备前先定 UI 交互原型的产品和技术负责人。整篇按“先看能不能跑、能跑多流畅、再往机台上搬”的顺序展开。
1. LVGL 模拟手机效果核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 开源嵌入式图形库 LVGL(Light and Versatile Graphics Library) |
| 开源协议 | MIT,可商用,社区活跃,官方持续维护 |
| 核心定位 | 在 PC 模拟器和 MCU / 开发板上绘制类手机界面 |
| 主要功能 | 控件、样式、主题、Flex / Grid 布局、动画、输入设备事件、字库、图片、滚动、屏幕切换 |
| 官方模拟器 | lv_sim_vscode_sdl 等官方模板,支持鼠标 / 键盘模拟触摸 |
| 可视化 UI 工具 | SquareLine Studio、EEZ Studio 等第三方工具,按你使用的 LVGL 版本确认兼容性 |
| 支持平台 | Windows / Linux / macOS 模拟器;STM32、ESP32 等 MCU;Linux 单板机 |
| 资源需求 | 模拟器由 PC 内存承担;嵌入式按官方低配参考 + 目标 MCU 实际评估,手机效果级别需要更多 RAM/Flash |
| 接口能力 | 不是 HTTP API,而是事件系统、输入设备驱动和 UI 回调,可与业务层解耦 |
| 批量任务 | 模拟器可脚本化定时截图批量归档;MCU 端用定时器 / 任务队列实现周期性刷新 |
| 适合场景 | 嵌入式 GUI 原型、智能硬件屏幕、仪表 / 家电 / 工控 HMI、嵌入式 UI 教学 |
注意一点:LVGL 模拟手机效果并不是要把手机系统完整复刻出来,而是在有限资源下还原“手机 UI 的手感”。真机上的高斯模糊、复杂背景虚化、高帧率动效,在低端 MCU 上要做取舍。
2. 适用场景与使用边界
先讲适合谁。最合适的是嵌入式 GUI 项目的早期阶段。你还没定屏幕尺寸、没选好主控时,先用 LVGL 模拟器按手机的比例搭一版界面,验证信息层级和交互流程;UI 确认后,再按目标平台裁剪组件和资源。其次是教学场景,LVGL 控件和事件模型覆盖了 GUI 开发最核心的概念,非常适合作为入门嵌入式图形开发的练习对象。智能手表、智能家居面板、手持设备、小型仪表盘的界面,也都能套用“手机效果”的布局思路。
不适合什么场景?不适合把 LVGL 当 Android / iOS 的替代品去开发复杂应用,它没有 WebView、系统级通知、应用进程管理这些能力。也不适合做重 3D 渲染、长文本排版和大量图片解码的场景,这些在 MCU 上成本过高。如果你的 UI 需要大量位图素材、复杂渐变和实时毛玻璃效果,先评估 MCU 的刷新带宽和内存是否扛得住。
使用边界要明确几件事。第一,UI 素材版权。不要直接从手机厂商固件、主题商店里拆图标、壁纸和字体,做产品时必须使用有授权的素材或自行设计。第二,肖像与隐私。如果项目后续接入摄像头、人脸或用户数据,要按实际产品形态做合规评估,开发阶段不要采集无关真实用户信息。第三,版本兼容。LVGL 从 v8 到 v9 有不少接口更名,教程代码不一定能直接跑通,以你下载版本的官方头文件和文档为准。第四,模拟器验证通过不等于 MCU 能跑,性能要以目标板实测为准。
3. LVGL 模拟手机效果环境准备
做手机效果的 UI,推荐先在 PC 模拟器上完成,再考虑移植到 MCU。三条路径对应不同目标:
路径 A:PC 模拟器(最推荐,先跑交互)
- 操作系统:Windows 10/11、Ubuntu、macOS 均可
- 工具:VS Code、CMake、make 或 ninja、Git
- 图形依赖:SDL2
- 好处:鼠标模拟点击和滑动,开发调试快,不用反复烧录
路径 B:ESP32(适合做无线产品原型)
- ESP-IDF v5.x
- 官方维护的 esp_lvgl_port 驱动层
- 屏幕多为 SPI / RGB 接口,触摸常用 I2C 电容屏
- 好处:可以直接验证触摸、低功耗、网络联动
路径 C:STM32(适合工控、仪表、小屏设备)
- STM32CubeMX 生成工程,常见 F103 / F407 / H750 / F429
- 屏幕驱动为 LTDC / SPI 屏,触摸芯片如 FT6236、GT911
- 好处:出货量大,资料多,LVGL 社区案例丰富
在准备环境时,建议先把下面几个检查项过一遍:系统是否安装 Git;是否安装了 CMake 和编译器;电脑是否能正常显示 SDL 窗口(远程桌面下需要留意渲染驱动);最终目标板的分辨率、色深是多少。色深直接写在 LVGL 配置里,模拟器和 MCU 保持一致,否则后期反复调样式。
4. LVGL 模拟器安装部署与启动
模拟器部分以官方常用的 VS Code + SDL 模板为例。仓库名是 lv_sim_vscode_sdl,使用--recursive克隆,把 LVGL 子模块一起拉下来。
# 示例命令,仓库地址以官方 GitHub 为准 git clone --recursive https://github.com/lvgl/lv_sim_vscode_sdl.git cd lv_sim_vscode_sdlUbuntu 上需要先装 SDL2 依赖:
sudo apt-get update sudo apt-get install -y libsdl2-dev build-essential cmake gitWindows 用户把 SDL2 开发库放到工程指定的目录,具体路径看仓库 README。然后构建并运行:
mkdir -p build && cd build cmake .. make -j4 ./lv_sim_vscode_sdl也可以直接用 VS Code 打开工程,按 README 配置好编译器后按任务键编译运行。启动后你会看到模拟器窗口,默认状态会加载官方示例或者一个空白屏。第一步建议先改lv_conf.h里的分辨率,模拟手机竖屏效果:
#define LV_HOR_RES 360 #define LV_VER_RES 640不同版本配置宏名略有差异,v8 和 v9 都用LV_HOR_RES/LV_VER_RES的思路不完全一致,以你的 lv_conf.h 模板为准。窗口尺寸不必和手机完全一样,但建议用竖屏比例验证布局。
如果启动后窗口黑屏、白屏或者乱闪,优先检查 SDL2 驱动和构建日志。远程桌面环境下 SDL 渲染可能异常,可以加上软件渲染相关环境变量测试,例如:
export SDL_VIDEODRIVER=x11 ./lv_sim_vscode_sdl这只是排查思路,实际以你的运行环境为准。
5. 功能测试与效果验证:手机界面拆解
手机效果的 UI 不是单控件堆砌,而是“框架 + 交互”的组合。下面按从简单到复杂拆开验证,每个模块都适合在模拟器里单独测试。
5.1 状态栏:基础容器与标签对齐
状态栏是手机 UI 的“第一眼”。LVGL 里没有现成的状态栏控件,直接用lv_obj作为容器,加两个lv_label左右对齐,取消滚动即可。这个测试能验证你对容器、对齐、样式的基本功。
/* LVGL v9 风格,v8 把 lv_screen_active 换成 lv_scr_act */ static void status_bar_create(lv_obj_t * scr) { lv_obj_t * bar = lv_obj_create(scr); lv_obj_set_size(bar, LV_PCT(100), 28); lv_obj_align(bar, LV_ALIGN_TOP_MID, 0, 0); lv_obj_remove_flag(bar, LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_style_bg_color(bar, lv_color_hex(0x1F1F1F), 0); lv_obj_t * clock = lv_label_create(bar); lv_label_set_text(clock, "09:41"); lv_obj_align(clock, LV_ALIGN_LEFT_MID, 10, 0); lv_obj_t * battery = lv_label_create(bar); lv_label_set_text(battery, LV_SYMBOL_CHARGE " 86%"); lv_obj_align(battery, LV_ALIGN_RIGHT_MID, -10, 0); }判断标准:窗口顶部出现一条深色状态栏,时间靠左、电量靠右,缩放窗口时状态栏宽度跟随变化。失败排查点通常是lv_obj_remove_flag没写,导致容器自身能滚动,或对齐方式写错。
5.2 主屏应用网格:Flex 布局
手机桌面本质是图标的网格。LVGL v9 里推荐用 Flex 或 Grid 布局做,不要在代码里手算坐标。这里用 Flex 换行排 12 个应用按钮:
static void home_screen_create(lv_obj_t * scr) { lv_obj_t * grid = lv_obj_create(scr); lv_obj_set_size(grid, LV_PCT(100), LV_PCT(100)); lv_obj_set_flex_flow(grid, LV_FLEX_FLOW_ROW_WRAP); lv_obj_set_flex_align(grid, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START); lv_obj_set_style_pad_row(grid, 20, 0); lv_obj_set_style_pad_column(grid, 20, 0); for (int i = 0; i < 12; i++) { lv_obj_t * btn = lv_button_create(grid); lv_obj_set_size(btn, 48, 48); lv_obj_t * label = lv_label_create(btn); lv_label_set_text(label, LV_SYMBOL_SETTINGS); lv_obj_center(label); } }这里顺便说清楚“容器”的概念。LVGL 中lv_obj本身就是万能容器,所有布局、背景、边框、圆角都通过它实现。手机桌面、通知面板、底部导航栏,本质都是不同样式的容器嵌套。如果你遇到“容器里的控件不受控”,先看父对象的 Flex / Grid 参数是不是设置正确,再看子对象是否设置了固定坐标把布局覆盖了。
5.3 屏幕切换与左右滑屏
手机效果的灵魂是滑屏。LVGL 有两种做法:一种是“全屏切换”,代码直接加载另一个 screen;另一种是“同屏横滑”,适合主屏多页面,推荐用lv_tileview。
全屏切换最简单:
void app_open(lv_obj_t * app_screen) { /* v9 风格,v8 时间参数顺序有差异,以当前版本头文件为准 */ lv_screen_load_anim(app_screen, 300, 0, LV_SCREEN_LOAD_ANIM_MOVE_LEFT, NULL); }主屏多页横滑用lv_tileview_create,每个 tile 放一页应用网格,用户左右滑动时自动吸附到下一 tile。tileview 是“左右滑屏”最接近手机桌面的控件,但它的接口在不同大版本略有变化,实际使用时先翻一下你本地版本的lv_tileview.h。
验证标准是:鼠标按住拖动页面,能随手指移动,松手后吸附到相邻页,没有明显的卡顿和回弹异常。如果拖动没反应,检查输入设备类型是否是 POINTER,以及目标对象是否允许滚动。
5.4 通知面板下拉动画:动画 API
手机控制中心/通知面板的核心是“下拉 + 回弹”。LVGL 动画 API 可以给任意对象做位置、透明度、大小动画。下面是一个从屏幕顶部滑出的面板示例:
static void anim_y_cb(void * var, int32_t v) { lv_obj_set_y((lv_obj_t *)var, v); } static void open_panel(lv_obj_t * panel) { lv_anim_t a; lv_anim_init(&a); lv_anim_set_var(&a, panel); lv_anim_set_exec_cb(&a, anim_y_cb); lv_anim_set_values(&a, -panel_height, 0); lv_anim_set_duration(&a, 250); lv_anim_set_path_cb(&a, lv_anim_path_ease_out); lv_anim_start(&a); }判断标准:面板从顶部平滑滑出,带缓动曲线,不跳变。动画卡顿的时候,不要先怀疑算法,优先看两个方向:一是对象在动画期间是不是频繁触发重绘;二是是否对大面积区域做了透明度动画,透明度叠加在低端 MCU 上开销很大。
5.5 开关控件与事件响应
手机设置页最常用的开关就是lv_switch。很多新手问“LVGL switch 按下不变化”,这里要重点说明:开关外观变化由LV_STATE_CHECKED控制,业务逻辑要监听LV_EVENT_VALUE_CHANGED,而不是LV_EVENT_CLICKED。
static void switch_event_cb(lv_event_t * e) { lv_obj_t * sw = lv_event_get_target(e); bool on = lv_obj_has_state(sw, LV_STATE_CHECKED); LV_LOG_USER("switch state: %s", on ? "ON" : "OFF"); } lv_obj_t * sw = lv_switch_create(parent); lv_obj_align(sw, LV_ALIGN_CENTER, 0, 0); lv_obj_add_event_cb(sw, switch_event_cb, LV_EVENT_VALUE_CHANGED, NULL);如果点击后开关不切换,常见原因有三个:一是事件时机写错,在CLICKED里读取状态,此时状态尚未更新;二是开关被其他透明控件或容器盖住了,点击事件没有落到 switch 上;三是自定义主题里把 checked 样式写成了和默认一样,视觉上看不出变化。排查时先打印事件回调是否触发,再检查样式。
5.6 按键事件与键盘控件
手机 UI 不只有触摸,还有物理按键和外部键盘。LVGL 有输入设备分组机制,lv_group可以把按钮、开关、滑块加入同一组,用方向键和确认键操作。这在带旋转编码器或按键的设备上很实用。
lv_group_t * g = lv_group_create(); lv_group_add_obj(g, btn_settings); lv_group_add_obj(g, btn_power);键盘控件lv_keyboard则可以给文本框弹出软键盘。模拟器里鼠标点击文本框,软键盘出现,键盘按键能被点击。验证这一项,能提前发现“焦点管理”和“键盘遮挡输入框”的问题。
5.7 中文字库与图片素材
手机 UI 必须有中文字库。LVGL 默认英文字库不包含中文,直接把lv_label_set_text设置成中文会显示方框。正确做法是用官方字库工具lv_font_conv或配套工具把需要的汉字子集生成.c文件,再配置到lv_conf.h。字库控制在常用字范围,能大幅压缩 Flash 占用。
同样,图片素材建议转成 LVGL 图片格式,而不是在 MCU 上直接解码 PNG/JPG。模拟器里可以直接加载图片路径,但在 MCU 上 PNG 解码需要额外库和内存,图片转 C 数组或.bin是更稳妥的方式。
6. 事件系统、消息接口与批量验证
LVGL 不是 Web 服务,没有 REST API,但它的接口能力体现在两块:输入设备接口和 UI 消息接口。对嵌入式项目来说,这两块就是“UI 层”与“业务层”的契约。
6.1 触摸屏接入接口
先把触摸驱动挂到 LVGL,硬件层只需要提供一个读取函数:
static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = my_touch_read_cb; lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv);my_touch_read_cb里把触摸芯片的坐标和按下状态写进lv_indev_data_t。只要这个接口稳定,模拟器里的 UI 交互可以原封不动地搬到真机上。这也解释了为什么优先在模拟器里做手机效果,因为交互逻辑和硬件解耦后,换屏幕、换主控的成本都低很多。
6.2 UI 消息总线与业务解耦
在 LVGL v9 中,官方提供了内部消息总线能力,可以订阅和发送特定主题的消息,用来解耦界面和业务逻辑。v8 则需要自己用回调数组或全局事件结构体实现。核心思路是:界面组件不直接调用业务函数,而是发消息;业务模块订阅消息后执行动作。手机设置页的开关就是一个典型例子:开关只负责发送“Wi-Fi 开关状态变化”,具体是开热点还是连路由,由业务层处理。这样 UI 改版时,业务代码不会跟着整个界面重构。
6.3 批量截图与效果归档
手机效果的 UI 往往有多个候选布局。可以在模拟器工程里增加一个“自动演示”模式:启动后按固定时间依次加载不同界面,并截图归档。Linux 上可以用 Xvfb 做无界面运行,适合在自动化环境里批量产出对比图:
# 无显示器环境批量截图示例,需要按实际环境调整 Xvfb :99 -screen 0 360x640x24 & DISPLAY=:99 ./lv_sim_vscode_sdl & sleep 5 import -window root screenshot_home.png sleep 2 import -window root screenshot_settings.png这种脚本不是为了炫技,而是让团队在 UI 评审时有统一的对比素材,避免每个人在本地看到的界面差异被当成开发问题。
7. 资源占用与性能观察
LVGL 模拟手机效果,最终要落到 MCU 上,资源占用是决定方案能否量产的关键。建议从三个维度观察:内存占用、CPU / 刷新帧率、存储占用。
7.1 内存占用观察
LVGL 有内置内存监控接口:
lv_mem_monitor_t mon; lv_mem_monitor(&mon); LV_LOG_USER("total=%d free=%d max_used=%d frag=%d%%", (int)mon.total_size, (int)mon.free_size, (int)mon.max_used, (int)mon.frag_pct);在模拟器里看这个输出,只能得到相对值,因为 PC 内存足够大,把LV_MEM_SIZE调小后才能模拟 MCU 的紧张状态。更有效的做法是:直接以目标 MCU 的实际 RAM 为准,在lv_conf.h里设置合理的LV_MEM_SIZE,让模拟器提前暴露内存溢出问题。
7.2 刷新率与 CPU 占用
lv_conf.h里的LV_USE_PERF_MONITOR打开后,界面上会叠加显示刷新帧率和 CPU 占用。v9 也提供了直接从显示驱动取帧率的接口,具体函数名以版本头文件为准。手机效果的动画多,判断流畅度的标准很简单:在目标分辨率下,常见操作(滑屏、下拉、开关切换)能否稳定达到设备要求的帧率,并且没有明显掉帧。
如果帧率上不去,按优先级排查:刷屏缓冲区是否配置为双缓冲;大面积透明度动画是否过多;字库是否过大导致刷新带宽不足;屏幕接口是并口、SPI 还是 RGB,是否和主控 DMA 配合。
7.3 降低资源占用的常用手段
内存优化是 LVGL 移植的高频话题。记住几个原则:字库按需子集化,不要整包挂所有汉字;图片用 LVGL 格式,不要 MCU 端解 PNG;动画避免大规模透明混合;能用内置 Symbol 字体做图标,就不要额外切图;减少不必要的样式属性,样式计算也会消耗 CPU;合理设置刷屏缓冲区大小,双缓冲和单缓冲的取舍要看屏幕控制器和 DMA 能力。
Flash 优化则主要靠lv_conf.h裁剪:不用的控件关掉对应宏,不用的字体、图片、脚本模块都关掉,能显著缩小固件体积。这也是“先在模拟器验证,再到 MCU 裁剪”的最佳实践来源。
8. LVGL 模拟手机效果常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 模拟器启动后窗口黑屏 | SDL2 渲染驱动异常、窗口未刷新 | 查看构建日志,确认是否有错误输出 | 检查 SDL2 安装,远程桌面切换软件渲染 |
| 中文显示为方框 | 字库不包含中文字符 | 检查 lv_conf.h 字体配置 | 用 lv_font_conv 生成中文字库子集 |
| switch 按下不变化 | 事件监听时机错误或样式未区分状态 | 打印事件回调,检查 checked 状态 | 监听 LV_EVENT_VALUE_CHANGED |
| 滑屏手势无反应 | 输入设备不是 POINTER,或对象禁止滚动 | 检查 indev_drv.type,检查 scrollable 标志 | 注册 POINTER 设备,恢复滚动标志 |
| 页面切换动画卡顿 | 刷屏缓冲区不足、透明动画过多 | 打开性能监控,观察帧率 | 双缓冲、减少透明度动画 |
| 内存不足 / 随机崩溃 | LV_MEM_SIZE 偏小、资源对象未释放 | 打印 lv_mem_monitor 数据 | 加大内存、销毁不再使用的对象、裁剪组件 |
| 模拟器效果正常,MCU 上显示异常 | 色深、分辨率、驱动不一致 | 对比 lv_conf.h 和屏幕参数 | 统一色深和分辨率,检查 LCD 初始化 |
| STM32 移植后无显示 | LTDC/SPI 初始化失败、帧缓冲地址不对 | 单独先点亮屏幕,再跑 LVGL | 先做 LCD 驱动自测,再加载 LVGL |
| ESP32 上旋转屏幕后异常 | 驱动层和 LVGL 旋转参数不匹配 | 确认芯片平台的官方支持情况 | 在初始化阶段完成旋转,避免运行中反复切换 |
| 编译报 undefined reference | 组件被裁剪或子模块未拉取 | 检查 lv_conf.h 和 git submodule | 重新 clone --recursive,补全依赖 |
这里单独说一下 ESP32 系列。最近很多人在 ESP32-P4 上跑 LVGL 遇到卡死或旋转异常的问题,从社区反馈来看,多数和图像缓冲、LTDC 时钟配置、以及在不同线程中访问 LVGL 上下文有关。稳妥的做法是:先把电脑模拟器上的 UI 跑稳定,再在 ESP32 上用官方维护的esp_lvgl_port接入屏幕和触摸,避免直接把模拟器工程的显示流程照搬过来。
9. 最佳实践与使用建议
第一,先小参数验证,再上完整 UI。第一次跑通 LVGL 模拟器时,不要一上来就做全套手机效果。先做单屏 3 个控件,确认编译、构建、刷新流程正常,再逐步增加状态栏、应用网格、动画。
第二,代码和资源分目录管理。建议把lv_conf.h、UI 代码、图片资源、字库资源、第三方库分开存放。图片和字库做批量转换脚本,每次出图后自动更新,避免手工导出的版本混乱。
第三,版本锁定。LVGL v9 和 v8 的接口差异不小,工程里明确记录版本号,升级前先看官方迁移文档。第三方 UI 工具生成的代码必须和你的 LVGL 版本匹配。
第四,建立“模拟器为主、真机为辅”的验证流程。模拟器负责验证交互、布局、状态逻辑;真机负责验证帧率、内存、触摸延迟、屏幕亮度等硬件相关体验。两端的数据和素材用同一套脚本生成,减少手工同步。
第五,批量任务和自动化要加日志。模拟器脚本截图时记录时间、分辨率、帧率,方便回溯。MCU 端如果有周期性 UI 刷新任务,要在任务里加超时保护和失败重试,防止 UI 卡死拖垮整个系统。
第六,合规边界不要踩。使用手机品牌图标、壁纸、字体前,确认授权;接入用户数据、人脸、声音相关功能时,严格遵守产品隐私规范和法律法规。LVGL 本身是 MIT 协议,但你的素材资源不一定可随意商用。
第七,发布或商用前做效果复核。模拟器里 60 帧不代表 MCU 上是 60 帧,不要凭感觉发布。建议在真机上录制一段关键操作视频,并记录帧率和内存曲线,作为版本验收依据。
10. 总结与下一步
LVGL 模拟手机效果最值得尝试的点,是它把“手机 UI 的高频交互”做成了一个可复用的嵌入式原型:状态栏、Flex 网格、tileview 横滑、panel 下拉、switch 事件、动画,这些模块几乎可以直接搬到实际产品里。第一次做,建议先在官方 VS Code + SDL 模拟器上验证主屏和滑屏,这是投入产出比最高的一步。
最容易踩的坑有三个:一是 v8 / v9 接口混用导致的编译报错;二是中文字库没有子集化,显示方框或占用过大;三是把模拟器性能当成 MCU 性能,真机上帧率崩了才开始排查。先把这三件事在本地跑明白,后续移植 STM32、ESP32 时能省很多时间。
下一步可以扩展的方向很多:用 SquareLine Studio 或 EEZ Studio 可视化拖拽生成 UI 初稿;把 UI 工程接入 MicroPython 版本 LVGL,快速做原型验证;在 ESP32 上接入 Touch 驱动和 Wi-Fi,把手机效果做成真正可交互的智能设备面板;进一步按产品需求裁剪 LVGL 组件,控制 Flash 和 RAM 成本。LVGL 的生态足够把你从“画界面”带到“做产品”这一步,关键是先把模拟器这条路打通。建议收藏备用,下次搭 LVGL 工程时直接按这个流程走一遍。