本项目的用户界面完全由 LVGL (v8) 驱动,源码位于 obj/screen/
目录下。以 screen_dashboard.c
为例,可以看出UI设计的核心思想。
1. 动态创建与布局
- 组件创建: 所有UI组件(对象)均通过代码动态创建,如
lv_obj_create
,lv_label_create
,lv_img_create
等,提供了极高的灵活性。 - Flexbox 布局: 仪表盘页面的卡片布局广泛采用了 LVGL 的 Flexbox 布局 (
LV_FLEX_FLOW_ROW_WRAP
)。这使得多个大小不一的卡片能够在一个可滚动的容器内自动对齐和换行,完美适配不同内容。 - 样式驱动: 通过自定义的样式 (
sh_style_card
,sh_style_text_zh
等) 来统一控件的外观,实现了UI的视觉一致性。
2. 事件驱动交互
- 事件回调: 用户的交互(如点击)是通过事件回调机制处理的。
lv_obj_add_event_cb
函数为一个对象(如卡片card_climate
)绑定一个LV_EVENT_CLICKED
事件和对应的处理函数 (on_card_climate_clicked
),从而实现页面跳转或功能触发。
3. 异步UI更新(多线程安全)
为了防止网络请求等耗时操作阻塞UI线程导致界面卡顿,项目采用了安全的多线程UI更新机制:
- 创建后台线程: 天气信息获取功能在一个独立的
pthread
线程 (weather_thread
) 中运行。这个线程可以安全地执行sleep
或进行阻塞的网络IO,而不会影响LVGL主循环。 lv_async_call
安全通信: 当后台线程成功获取数据并需要更新UI(如天气图标和温度)时,它不能直接调用LVGL的函数。而是通过lv_async_call
将一个更新函数 (apply_weather_cb
) 和所需数据“派发”给LVGL的主循环。LVGL会在安全的时机(下一个lv_timer_handler()
周期)执行这个函数,从而避免了多线程冲突。这是在LVGL中进行线程安全UI更新的标准范式。