Screen Manager
管理多个界面(Screen)的创建、切换与输入事件分发。LVGL 中推荐基于 lv_group_t 的原生事件机制(方式一),仅在资源极度受限且交互极简的场景下才考虑手动路由(方式二)。
方式一
利用 lv_group_t 接收输入事件,通过 lv_indev_set_group() 切换焦点,由 LVGL 事件循环自动派发 LV_EVENT_KEY。
lv_obj_add_event_cb(screen, key_cb, LV_EVENT_KEY, NULL);
lv_group_add_obj(group, screen);
detail.c
static lv_obj_t *screen;
static lv_group_t *group;
// 对完提供获取group
lv_group_t * detail_get_group(void)
{
return group;
}
// 接收 LV_EVENT_KEY 的回调,在这里根据输入的按键处理业务需求
static void key_cb(lv_event_t *e)
{
uint32_t key = lv_event_get_key(e);
printf("key=%d\n", key);
}
// 创建界面
lv_obj_t * create_detail(void)
{
screen = lv_obj_create(NULL);
group = lv_group_create();
//这里重要,screen
lv_obj_add_event_cb(screen, key_cb, LV_EVENT_KEY, NULL);
lv_group_add_obj(group, screen);
return scr;
}
screen_manager.c
// 界面枚举,每个界面对应一个枚举
typedef enum {
SCREEN_MASTER,
SCREEN_SETTINGS,
SCREEN_DETAIL,
SCREEN_COUNT,
} screen_id_t;
// 界面结构体,
typedef struct {
lv_obj_t *screen; // 界面screen本身
lv_group_t *group;// group组
} screen_entry_t;
// 保存界面的数组
static screen_entry_t screens[SCREEN_COUNT];
// 初始化创建所有界面
void screen_mgr_init(void)
{
screens[SCREEN_MASTER] = (screen_entry_t){ create_master(), master_get_group() };
screens[SCREEN_SETTINGS]= (screen_entry_t){ create_settings(), settings_get_group() };
screens[SCREEN_DETAIL] = (screen_entry_t){ create_detail(), detail_get_group() };
}
// 界面切换
void screen_mgr_switch(screen_id_t id) //传入screen_id_t枚举
{
lv_scr_load(screens[id].scr);//切换时,加载一个界面
lv_indev_set_group(indev_get(), screens[id].grp);//切换界面后,设置输入事件的焦点到这个界面的group
}
方式二
判断当前所在的界面,输入事件触发时调用这个界面的回调key_cb
detail.c
static lv_obj_t *scr;
// 只需要提供回调函数就好
void detail_key_cb(uint32_t key)
{
printf("detail->key=%d\n", key);
//处理
}
lv_obj_t * create_detail(void)
{
scr = lv_obj_create(NULL);
// 不需要任何操作
return scr;
}
screen_manager.c
typedef enum {
SCREEN_MASTER,
SCREEN_SETTINGS,
SCREEN_DETAIL,
SCREEN_COUNT,
} screen_id_t;
static lv_obj_t *screens[SCREEN_COUNT];
static screen_id_t now_screen; //当前界面
void screen_mgr_init(void)
{
screens[SCREEN_MASTER] = create_master();
screens[SCREEN_SETTINGS]= create_settings();
screens[SCREEN_DETAIL] = create_detail();
}
void screen_mgr_switch(screen_id_t id)
{
lv_scr_load(screens[id]);//切换时,加载一个界面
now_screen = id;
}
//获取当前界面
screen_id_t get_now_screen(void)
{
return now_screen;
}
//界面路由处理
typedef void (*key_handler_t)(uint32_t);
static const key_handler_t key_handlers[SCREEN_COUNT] = {
[SCREEN_MASTER] = master_key_cb,
[SCREEN_SETTINGS] = settings_key_cb,
[SCREEN_DETAIL] = detail_key_cb,
};
void screen_mgr_dispatch_key(uint32_t key)
{
if (now_screen < SCREEN_COUNT && key_handlers[now_screen]) {
key_handlers[now_screen](key);
}
}
evdev.c
void evdev_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
data->key = last_key;
data->state = last_state;
struct input_event ev;
if (read(evdev_fd, &ev, sizeof(ev)) != sizeof(ev))
return;
last_key = k;
last_state = ev.value == 1 ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
if (ev.value == 1) { // ← 只处理按下
screen_mgr_dispatch_key(k);
}
}