这次我们来看一个基于 LVGL 的嵌入式 UI 项目,它专门针对圆形屏幕设计了音频播放器的用户界面。对于从事智能手表、智能家居面板、便携式音乐播放器等圆形屏幕设备开发的工程师来说,如何在小内存、低功耗的 MCU 上实现流畅且美观的交互,一直是个挑战。这个项目提供了一个现成的解决方案,将 LVGL 的轻量级图形库与音频播放功能结合,直接在圆形画布上构建了一套完整的音频播放 UI。
这个项目的核心价值在于,它不是一个简单的演示,而是一个可以直接集成到产品中的模块。它解决了圆形屏幕 UI 开发中的几个痛点:控件适配、动画流畅度、内存占用以及音频解码与 UI 的协同。如果你正在为 ESP32、STM32 等微控制器寻找一个既能播放音频(如 MP3、WAV)又具备精美圆形 UI 的参考实现,这个项目值得深入研究。
本文会带你从零开始,理解这个项目的架构,完成在 PC 模拟器上的环境搭建与运行,并最终将其移植到实际的硬件开发板(如 ESP32)上。我们会重点关注其资源占用、UI 响应速度、音频播放的稳定性,以及如何根据你的硬件进行定制化修改。无论你是想快速评估,还是计划将其用于产品原型,都能在文中找到对应的路径。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 嵌入式图形界面 (GUI) 与音频播放集成项目 |
| 核心库 | LVGL (Light and Versatile Graphics Library) |
| 目标平台 | 支持 LVGL 的嵌入式平台,如 ESP32、STM32 等 |
| 主要功能 | 在圆形屏幕上实现音频播放器 UI:播放/暂停、上一曲/下一曲、进度条、音量控制、歌曲列表等 |
| UI 特性 | 专为圆屏设计,控件布局、动画效果均适配圆形区域 |
| 音频支持 | 依赖于平台音频驱动(如 I2S),通常支持 PCM、MP3、WAV 等格式(需具体解码库) |
| 开发环境 | 可在 LVGL 官方 PC 模拟器上快速开发与调试 |
| 资源占用 | 取决于 LVGL 配置和分辨率,通常需要几十 KB RAM 和几百 KB Flash |
| 启动方式 | 通过标准 LVGL 项目结构编译运行,或使用 PlatformIO、ESP-IDF 等集成开发环境 |
| 接口能力 | 提供 LVGL 对象(按钮、滑块、标签等)的事件回调接口,可自定义业务逻辑 |
| 适合场景 | 圆形屏幕的智能穿戴设备、家用电器面板、工业仪表盘等需要音频反馈的嵌入式产品 |
2. 适用场景与使用边界
这个项目非常适合以下几类开发者和场景:
- 智能穿戴设备开发者:正在开发圆形表盘的智能手表或手环,需要内置音乐播放或语音提示功能。
- 智能家居产品经理/工程师:设计带圆形屏幕的智能音箱、温控面板或中控屏,希望集成本地音频播放和交互式 UI。
- 嵌入式 UI 学习者:希望学习如何将 LVGL 应用于非矩形屏幕,并处理 UI 与底层硬件(如音频编解码器)的交互。
- 快速原型构建者:需要在短时间内为硬件验证一个具备音频播放能力的圆形 UI 演示。
使用边界与注意事项:
- 硬件依赖:项目运行需要支持 LVGL 的 MCU 以及一个圆形显示屏(如 GC9A01、ST7789v 等驱动芯片)。音频播放功能需要额外的硬件支持,如 I2S 接口的 DAC 或音频编解码芯片(如 MAX98357A)。
- 性能门槛:UI 流畅度和音频解码同时进行对 MCU 主频和内存有一定要求。对于低端 MCU,可能需要权衡动画复杂度和音频解码质量。
- 功能完整性:项目主要提供 UI 框架和与音频播放器的对接示例。完整的音频解码器(如 MP3 解码库)、文件系统读取、网络流媒体等功能,可能需要开发者自行集成或选用更强大的硬件平台(如 ESP32-A1S 模组)。
- 版权与合规:若播放的音频内容涉及版权,务必确保拥有合法授权。在涉及语音提示或录音功能时,需注意用户隐私保护,符合相关法律法规。
3. 环境准备与前置条件
在开始动手之前,请确保你的开发环境满足以下基本要求。
3.1 硬件准备(用于最终移植)
- 微控制器开发板:如 ESP32-DevKitC、STM32F4 Discovery 等。
- 圆形显示屏模块:常见的有 GC9A01(240x240)、ST7789v(240x240)等 SPI 或并行接口的屏幕。
- 音频输出设备:可以是 I2S 接口的 DAC 模块(如 MAX98357A 模块),或者开发板自带的音频输出接口。
- 连接线:杜邦线,用于连接屏幕、音频模块与开发板。
- 存储设备:SD 卡或 SPI Flash,用于存放音频文件(如果播放本地文件)。
3.2 软件准备(用于模拟器开发与调试)
在将项目移植到硬件前,强烈建议先在 PC 上的 LVGL 模拟器中运行和修改 UI,这能极大提高开发效率。
- 操作系统:Windows 10/11, Linux 或 macOS。
- 代码编辑器:Visual Studio Code (VSCode) 是首选,拥有丰富的 LVGL 插件。
- 编译器与构建工具:
- PC 模拟器:需要安装 GCC/MinGW 或 MSVC (Windows)、GCC (Linux/macOS)。
- ESP32:需要安装 ESP-IDF 或 PlatformIO 扩展。
- STM32:需要安装 ARM GCC 工具链和 STM32CubeIDE 或 PlatformIO。
- LVGL PC 模拟器项目:这是快速启动的关键。可以从 LVGL 官方 GitHub 仓库获取。
- 必要的软件库:
- SDL2 (用于模拟器显示和输入)。
- (可选)FFmpeg 库或其它音频库,用于在模拟器中模拟音频播放回调。
4. 安装部署与启动方式
我们将分两步走:首先在 PC 模拟器上运行和体验项目,然后再移植到硬件。
4.1 在 LVGL PC 模拟器上运行
这是最快捷的评估方式,无需硬件。
获取 LVGL 模拟器项目:
git clone --recursive https://github.com/lvgl/lv_port_pc_vscode.git cd lv_port_pc_vscode集成圆屏音频播放器 UI 代码:
- 将你要评估的 “LVGL圆屏播放音频创意UI” 项目中的 UI 相关源文件(通常是
.c和.h文件)复制到模拟器项目的src目录下。 - 主要需要复制的是创建屏幕(
lv_scr_act())和所有控件(按钮、滑块、标签、图像等)的代码。 - 同时,需要将项目中的图片、字体等资源文件复制到
assets目录。
- 将你要评估的 “LVGL圆屏播放音频创意UI” 项目中的 UI 相关源文件(通常是
模拟音频播放逻辑:
- 由于 PC 上没有真实的 I2S 硬件,你需要用一个软件回调来模拟音频播放。例如,在
main.c中,可以将播放/暂停按钮的回调函数链接到一个模拟函数,该函数打印日志或调用系统的音频播放 API(如 SDL_mixer)。 - 关键是在 UI 的回调中,更新进度条、时间标签等状态,模拟播放过程。
- 由于 PC 上没有真实的 I2S 硬件,你需要用一个软件回调来模拟音频播放。例如,在
编译与运行:
- 用 VSCode 打开项目文件夹。
- 安装推荐的扩展(如 C/C++)。
- 根据你的平台,在终端运行构建命令。通常项目会提供
build.sh(Linux/macOS) 或使用 CMake。
# Linux/macOS 示例 mkdir build && cd build cmake .. make -j4 ./lvgl_example- 运行后,会出现一个模拟的圆形窗口,展示完整的音频播放器 UI,你可以用鼠标点击按钮进行交互。
4.2 移植到硬件平台(以 ESP32 为例)
当模拟器 UI 调试满意后,即可移植到真实硬件。
创建 ESP-IDF 项目:
mkdir -p ~/esp/audio_player_ui cd ~/esp/audio_player_ui cp -r $IDF_PATH/examples/peripherals/lvgl . # 复制 LVGL 示例作为基础 # 或者使用 PlatformIO 创建新项目,选择 ESP32 和 LVGL 库。集成 UI 与驱动:
- 将模拟器中调试好的 UI 源文件和资源文件复制到 ESP32 项目的
main目录。 - 配置显示屏驱动:修改
lv_conf.h和lvgl_helpers.h/c,设置正确的屏幕分辨率(240x240)、驱动芯片类型(GC9A01)和 SPI 引脚。 - 集成音频驱动:根据你使用的音频模块(如 MAX98357A),配置 ESP32 的 I2S 引脚和参数。可以使用
esp-adf(乐鑫音频开发框架)中的相关示例代码。
- 将模拟器中调试好的 UI 源文件和资源文件复制到 ESP32 项目的
连接音频播放逻辑:
- 在 UI 的播放按钮回调函数中,不再调用模拟函数,而是调用
i2s_stream_start()等实际的音频播放 API。 - 创建一个任务(FreeRTOS Task)或定时器,用于更新播放进度,并调用
lv_bar_set_value()和lv_label_set_text()来刷新 UI。
- 在 UI 的播放按钮回调函数中,不再调用模拟函数,而是调用
编译与烧录:
idf.py set-target esp32 idf.py menuconfig # 配置 LVGL 内存大小、堆栈大小等 idf.py build idf.py -p /dev/ttyUSB0 flash monitor
5. 功能测试与效果验证
在模拟器和硬件上,都需要对核心功能进行验证。
5.1 UI 渲染与交互测试
- 测试目的:验证圆形 UI 是否正常显示,所有控件是否响应输入。
- 操作步骤:
- 启动程序(模拟器或硬件上电)。
- 观察屏幕是否点亮,并完整绘制出圆形播放器界面(专辑封面、进度条、控制按钮等)。
- 使用鼠标(模拟器)或触摸屏/按键(硬件)点击“播放/暂停”按钮。
- 点击“上一曲”、“下一曲”按钮。
- 拖动“进度条”滑块。
- 拖动“音量”滑块。
- 预期结果:
- 按钮应有按下态视觉效果(颜色或形状变化)。
- 点击播放/暂停,按钮图标应在“播放”和“暂停”状态间切换。
- 点击上一曲/下一曲,专辑封面或歌曲名标签应发生变化(模拟或实际)。
- 拖动进度条,进度指示应跟随移动,时间标签应更新。
- 拖动音量条,音量图标或数值应变化。
- 判断成功:所有视觉反馈与交互逻辑符合预期。
- 常见失败原因:
- 屏幕驱动初始化失败:检查 SPI 引脚配置、屏幕初始化序列。
- 触摸屏或按键无响应:检查输入设备驱动和 LVGL 输入设备注册。
- 控件事件未绑定:检查
lv_obj_add_event_cb()函数调用。
5.2 音频播放功能测试
- 测试目的:验证 UI 能控制音频硬件正常播放、暂停、切换。
- 操作步骤(硬件):
- 将测试音频文件(如
test.mp3)放入 SD 卡或 SPIFFS 文件系统。 - 在代码中硬编码或通过列表加载该文件路径。
- 点击 UI 上的“播放”按钮。
- 聆听扬声器或耳机是否有声音输出。
- 点击“暂停”按钮,声音应停止。
- 点击“下一曲”(如果有多个文件),应播放下一首。
- 拖动进度条,尝试实现快进/快退(此功能需要音频解码器支持)。
- 将测试音频文件(如
- 预期结果:
- 音频播放流畅,无杂音或卡顿。
- 播放/暂停控制即时生效。
- 进度条应随时间自动前进。
- 判断成功:音频输出与控制逻辑正常。
- 常见失败原因:
- I2S 配置错误:检查时钟、数据格式、引脚分配。
- 音频文件格式不支持:确认解码库支持该格式(MP3, WAV, AAC)。
- 内存不足:音频解码缓冲区可能过大,尝试减小缓冲区大小或优化内存配置。
- 文件读取失败:检查文件系统挂载和文件路径。
5.3 性能与压力测试
- 测试目的:评估系统在 UI 动画与音频解码同时运行时的稳定性。
- 操作步骤:
- 让系统持续播放音频。
- 快速、连续地操作 UI 按钮,模拟用户频繁交互。
- 观察是否有界面卡顿、音频断音、系统重启等现象。
- 预期结果:系统运行稳定,UI 响应及时,音频播放不间断。
- 判断成功:长时间运行(如 30 分钟)无异常。
- 常见失败原因:
- 堆栈溢出:UI 任务或音频任务的堆栈设置过小。在
menuconfig中增加LVGL_TASK_STACK_SIZE和音频任务的堆栈。 - 内存泄漏:在切换歌曲或界面时,未正确释放前一次分配的内存(如图片缓存)。使用 ESP-IDF 的内存调试工具检查。
- 中断冲突:SPI(屏幕)、I2S(音频)、SDMMC(读卡)可能共用中断或 DMA 通道,造成冲突。调整外设使用的 DMA 通道或优先级。
- 堆栈溢出:UI 任务或音频任务的堆栈设置过小。在
6. 接口 API 与事件回调设计
本项目本质上是 LVGL 应用程序,其“接口”主要体现在 LVGL 对象的事件回调函数上。理解如何扩展这些回调是定制功能的关键。
6.1 核心事件回调示例
假设我们有一个播放/暂停按钮play_btn和一个进度条progress_bar。
// 在创建UI的函数中 lv_obj_t *play_btn = lv_btn_create(lv_scr_act()); lv_obj_t *progress_bar = lv_bar_create(lv_scr_act()); // 为播放按钮添加点击事件回调 lv_obj_add_event_cb(play_btn, play_btn_event_handler, LV_EVENT_CLICKED, NULL); // 为进度条添加拖动事件回调 lv_obj_add_event_cb(progress_bar, progress_bar_event_handler, LV_EVENT_VALUE_CHANGED, NULL);6.2 回调函数实现示例
// 播放/暂停按钮事件处理函数 static void play_btn_event_handler(lv_event_t *e) { lv_event_code_t code = lv_event_get_code(e); lv_obj_t *btn = lv_event_get_target(e); if(code == LV_EVENT_CLICKED) { // 获取当前按钮状态(可通过标签或用户数据存储) static bool is_playing = false; is_playing = !is_playing; if(is_playing) { // 1. 更新按钮图标为“暂停” lv_label_set_text(lv_obj_get_child(btn, 0), LV_SYMBOL_PAUSE); // 2. 调用底层音频播放器开始播放 audio_player_start(); // 3. 启动一个定时器,用于更新进度条 lv_timer_resume(progress_update_timer); } else { // 1. 更新按钮图标为“播放” lv_label_set_text(lv_obj_get_child(btn, 0), LV_SYMBOL_PLAY); // 2. 调用底层音频播放器暂停 audio_player_pause(); // 3. 暂停更新进度条的定时器 lv_timer_pause(progress_update_timer); } } } // 进度条更新定时器回调 static void progress_update_timer_cb(lv_timer_t *timer) { // 1. 从音频播放器获取当前播放位置(单位:秒) uint32_t current_time = audio_player_get_current_time(); uint32_t total_time = audio_player_get_total_time(); // 2. 计算进度百分比 lv_coord_t progress = (total_time > 0) ? (current_time * 100 / total_time) : 0; // 3. 更新进度条值 lv_bar_set_value(progress_bar, progress, LV_ANIM_ON); // 4. 更新时间标签 (例如: "01:23 / 04:56") char time_str[20]; snprintf(time_str, sizeof(time_str), "%02d:%02d / %02d:%02d", current_time / 60, current_time % 60, total_time / 60, total_time % 60); lv_label_set_text(time_label, time_str); }6.3 与外部系统集成
你可以通过这些事件回调,轻松地将 UI 与更复杂的系统连接:
- 蓝牙控制:在回调函数中发送蓝牙 AVRCP 命令。
- 网络请求:切换歌曲时,从网络 API 获取下一首歌曲的元数据(专辑图、名称)。
- 传感器交互:抬起手腕(加速度计)自动点亮屏幕,或旋转表冠(编码器)调节音量。
7. 资源占用与性能优化
在资源受限的嵌入式设备上,优化至关重要。
7.1 内存占用分析
- LVGL 本身:通过
lv_conf.h配置。关键配置项:#define LV_MEM_SIZE (48 * 1024U) // 建议从32KB开始测试,根据控件数量增加 #define LV_DISP_DEF_REFR_PERIOD 30 // 刷新周期(ms),值越大CPU占用越低,但流畅度下降 #define LV_DPI_DEF 130 // 根据屏幕实际DPI设置,影响字体和图像渲染 - 帧缓冲区:双缓冲区能提升流畅度,但会占用 2 * 屏幕分辨率 * 颜色深度 的内存。对于 240x240 RGB565 屏幕,单缓冲区需 2402402 = 115200 字节 (约112.5KB)。如果内存紧张,可使用单缓冲区或部分缓冲区。
- 图片与字体:是 Flash 占用的大头。
- 优化图片:使用 LVGL 的在线图片转换工具,将 PNG/JPG 转换为 C 数组,并选择适当的颜色格式(如 RGB565)和压缩。
- 优化字体:仅包含 UI 中实际用到的字符集(
LV_FONT_SIMPLIFIED_CHINESE包含很多字),可以使用 LVGL 的字体转换工具生成自定义字体文件。
7.2 CPU 占用与渲染性能
- 监控工具:使用
lv_timer_get_idle()函数可以获取系统空闲时间百分比,间接反映 CPU 负载。 - 降低刷新率:非必要不刷新。对于静态元素多的界面,可以设置
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN)或lv_obj_add_state(obj, LV_STATE_DEFAULT)来减少重绘区域。 - 简化动画:减少同时进行的复杂动画数量。使用
LV_ANIM_OFF或更短的动画时间。 - 音频解码优化:如果音频解码占用大量 CPU,考虑:
- 使用硬件解码(如果 MCU 支持)。
- 降低音频采样率(如从 44.1kHz 降到 22.05kHz)。
- 使用计算量更小的解码算法(如 ADPCM 代替 MP3)。
7.3 存储优化
- 文件系统:如果音频文件较多,使用 SPIFFS 可能效率较低。考虑使用 FATFS 配合 SD 卡。
- 资源管理:不要一次性将所有歌曲的封面图片加载到内存。使用
lv_img_set_src()时,可以设置LV_IMG_SRC_FILE从文件系统动态加载,并配合缓存策略。
8. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 屏幕白屏或花屏 | 1. 屏幕驱动初始化序列错误。 2. SPI 时钟速率过高。 3. 电源或背光未开启。 | 1. 用逻辑分析仪抓取 SPI 时序,与屏幕数据手册对比。 2. 降低 SPI 时钟频率。 3. 检查屏幕的 VCC、GND、背光引脚电压。 | 1. 仔细核对并修正初始化命令序列。 2. 在 lv_conf.h或驱动代码中降低 SPI 频率。3. 确保硬件连接正确,背光被点亮。 |
| 触摸无反应 | 1. 触摸屏驱动未正确注册到 LVGL。 2. 触摸屏 I2C/SPI 通信失败。 3. 触摸屏校准数据错误。 | 1. 检查lv_port_indev_init()中是否添加了触摸屏设备。2. 检查 I2C/SPI 引脚和地址。 3. 运行 LVGL 的触摸校准示例。 | 1. 确保lv_indev_drv_register()被调用。2. 修复通信问题。 3. 重新校准并保存触摸参数。 |
| UI 严重卡顿 | 1. LVGL 任务堆栈溢出。 2. 帧缓冲区设置过小或内存不足。 3. 过于复杂的动画或频繁全局重绘。 | 1. 查看系统日志是否有堆栈溢出警告。 2. 监控 lv_timer_get_idle()值,如果很低说明 CPU 忙。3. 使用 LVGL 的性能分析器(如果启用)。 | 1. 增加LVGL_TASK_STACK_SIZE。2. 增加 LV_MEM_SIZE或优化内存使用。3. 简化 UI,减少动画,使用局部刷新 lv_obj_invalidate_area()。 |
| 播放音频时系统重启 | 1. 音频任务堆栈溢出。 2. I2S DMA 缓冲区配置错误导致内存访问越界。 3. 电源带载能力不足。 | 1. 检查音频任务的堆栈大小。 2. 检查 I2S 配置,特别是 DMA 缓冲区数量和大小。 3. 测量播放音频时电源电压是否被拉低。 | 1. 增加音频任务堆栈。 2. 调整 I2S DMA 缓冲区大小,确保其对齐且未越界。 3. 为音频功放模块提供独立电源或增加电源滤波电容。 |
| 进度条不更新或跳跃 | 1. 更新进度条的定时器周期设置不当。 2. 从音频解码器获取的时间信息不准确或不同步。 3. 回调函数内执行了耗时操作,阻塞了 LVGL 主任务。 | 1. 检查定时器回调函数是否被正常调用。 2. 打印获取到的当前时间和总时间,看是否连续。 3. 在回调函数中只做最简单的赋值操作,将复杂逻辑移到其他任务。 | 1. 调整定时器周期(如 200ms)。 2. 确保音频解码器提供的时间基是稳定的,或使用音频数据已播放的字节数来计算进度。 3. 使用队列(Queue)或信号量(Semaphore)进行任务间通信,避免阻塞。 |
| 切换歌曲时界面卡死 | 1. 在事件回调中进行了文件系统操作(如读取下一首歌),该操作阻塞时间过长。 2. 切换时未正确释放上一首歌的资源(如解码器实例、文件句柄)。 | 1. 在回调中只发送切换请求,在独立的任务中执行实际的加载和解码操作。 2. 检查资源释放代码,确保没有内存泄漏。 | 1. 将耗时的 IO 和解析操作放入低优先级任务。 2. 实现严格的资源管理生命周期,使用 malloc/free或 RAII 模式(C++)。 |
9. 最佳实践与使用建议
开发流程建议:
- 模拟器先行:80% 的 UI 逻辑和布局调整应在 PC 模拟器上完成,效率远高于反复烧录硬件。
- 版本控制:对 UI 资源(图片、字体)和配置文件(
lv_conf.h)进行版本管理,便于回溯和对比不同硬件配置下的效果。 - 分模块测试:先确保屏幕驱动和触摸驱动单独工作正常,再集成 LVGL;先确保音频播放单独工作正常,再与 UI 联动。
代码组织建议:
- UI 与逻辑分离:将创建 UI 控件的代码放在
ui.c中,将与硬件交互的音频控制代码放在audio_player.c中。两者通过清晰定义的接口(如函数指针、事件队列)通信。 - 使用 LVGL 样式:统一管理控件的颜色、字体、边距等属性,而不是硬编码在每个控件创建函数里。这便于后期整体换肤。
- 合理使用用户数据:
lv_obj_set_user_data(obj, &my_data)可以将业务数据(如歌曲索引、播放状态)与 LVGL 对象关联,方便在事件回调中获取。
- UI 与逻辑分离:将创建 UI 控件的代码放在
性能与资源最佳实践:
- 懒加载资源:对于多级菜单或复杂页面,不要一次性创建所有控件。使用
lv_obj_del()和lv_obj_create()动态管理。 - 图片缓存策略:对于频繁使用的图标,可以加载到内存;对于不常用的专辑大图,从文件系统读取并设置较小的缓存。
- 功耗考虑:在播放音频时,可以适当提高 CPU 频率;在待机界面,降低屏幕刷新率甚至关闭屏幕背光,以节省电量。
- 懒加载资源:对于多级菜单或复杂页面,不要一次性创建所有控件。使用
产品化建议:
- 异常处理:增加看门狗(Watchdog),防止程序跑飞。对文件读取失败、内存分配失败等情况要有降级处理(如显示默认图片、播放错误提示音)。
- 用户数据持久化:将音量设置、播放模式(单曲循环、列表循环)等用户偏好保存到非易失性存储(NVS)。
- 工厂测试模式:预留一个硬件按键组合,进入测试模式,自动循环测试屏幕显示、触摸、音频输出、按键等功能,方便生产环节质检。
10. 总结与下一步
这个“LVGL圆屏播放音频创意UI”项目为嵌入式圆形屏幕设备开发提供了一个高起点。它最值得尝试的点在于,将成熟的 LVGL 生态与具体的音频播放场景深度结合,给出了一个可直接运行、易于修改的完整范例。你最先应该验证的是在模拟器上跑通整个 UI 交互流程,这能帮你快速理解其代码结构。
最容易踩的坑集中在硬件适配层:屏幕驱动初始化、触摸校准、I2S 音频配置。建议按照“先显示,再触摸,最后音频”的顺序逐个击破。当硬件基础打牢后,丰富的 LVGL 控件和事件机制能让你的创意快速实现。
下一步,你可以基于此项目进行多方向扩展:
- 功能增强:添加蓝牙耳机连接管理、均衡器设置、歌词同步显示(LRC)功能。
- 交互升级:结合旋转编码器或手势传感器,实现更自然的交互(旋转表冠调音量,上下滑切歌)。
- 云端集成:让设备通过 Wi-Fi 连接音乐流媒体服务,播放在线歌曲。
- 多语言支持:利用 LVGL 的字体引擎,轻松添加多语言歌曲信息显示。
建议将本文作为你的开发路线图,收藏备用。从模拟器到硬件,从基础播放到功能扩展,每一步都稳扎稳打,你就能高效地将这个精美的圆形音频播放 UI 应用到自己的产品中。