Page 开发模式

当前实现更新

HelloEasyPage 中的 Toast 也需要在初始化时直接传入 core

egui_toast_std_init((egui_toast_t *)&toast, core);
egui_toast_set_as_default((egui_toast_t *)&toast);

后续 egui_page_base_show_toast_info(...) 会直接使用 Page 自身已经绑定好的 core

Page 是 EmbeddedGUI 提供的轻量级多页面管理方案。相比 Activity 的完整生命周期和栈管理,Page 模式更简单直接,特别适合 RAM 资源紧张的嵌入式场景。

Page 生命周期

Page 的生命周期只有两个状态:

Open  ->  Close

状态

说明

on_open

页面打开,初始化所有控件和资源,将视图添加到 page

on_close

页面关闭,销毁所有控件和资源(如停止定时器)

核心 API:

// Page 基类 API 虚函数表
struct egui_page_base_api
{
    void (*on_open)(egui_page_base_t *self);
    void (*on_close)(egui_page_base_t *self);
    // ...
};

// 打开/关闭 Page
void egui_page_base_open(egui_page_base_t *self);
void egui_page_base_close(egui_page_base_t *self);

设计原则:同一时刻只有一个 Page 处于 Open 状态。切换页面时,先 close 当前 Page,再 open 新 Page。

Page 结构体定义

每个 Page 是一个独立的结构体,包含 egui_page_base_t 基类和页面专属的控件与数据:

struct egui_page_0
{
    egui_page_base_t base;      // 继承基类

    int index;
    char label_str[20];

    egui_timer_t timer;         // 页面专属定时器

    egui_view_linearlayout_t layout_1;
    egui_view_label_t label_1;
    egui_view_button_t button_1;
    egui_view_button_t button_2;
    egui_view_image_t image_1;
};

on_open 中初始化所有控件,在 on_close 中清理资源(如停止定时器)。

Union 内存优化

这是 Page 模式最大的优势。由于同一时刻只有一个 Page 处于活跃状态,可以用 union 让所有 Page 共享同一块内存:

// 定义 Page union,所有 Page 共享内存
union page_array
{
    egui_page_0_t page_0;
    egui_page_1_t page_1;
    egui_page_2_t page_2;
};

static union page_array g_page_array;

实际 RAM 占用 = max(sizeof(page_0), sizeof(page_1), sizeof(page_2)),而非三者之和。

页面切换

页面切换的核心逻辑:

static egui_page_base_t *current_page = NULL;

void uicode_switch_page(int page_index)
{
    egui_core_t *core = egui_toast_get_core((egui_toast_t *)&toast);

    // 1. 关闭当前 Page
    if (current_page)
    {
        egui_page_base_close(current_page);
    }

    // 2. 初始化新 Page(在 union 内存上重新构造)
    switch (page_index)
    {
    case 0:
        egui_page_0_init((egui_page_base_t *)&g_page_array.page_0, core);
        current_page = (egui_page_base_t *)&g_page_array.page_0;
        break;
    case 1:
        egui_page_1_init((egui_page_base_t *)&g_page_array.page_1, core);
        current_page = (egui_page_base_t *)&g_page_array.page_1;
        break;
    // ...
    }

    // 3. 打开新 Page
    egui_page_base_open(current_page);
}

前进和后退封装:

int uicode_start_next_page(void)
{
    int page_index = index + 1;
    if (page_index >= UICODE_MAX_PAGE_NUM)
    {
        egui_page_base_show_toast_info(current_page, "No more next page");
        return -1;
    }
    uicode_switch_page(page_index);
    return 0;
}

int uicode_start_prev_page(void)
{
    int page_index = index - 1;
    if (page_index < 0)
    {
        egui_page_base_show_toast_info(current_page, "No more previous page");
        return -1;
    }
    uicode_switch_page(page_index);
    return 0;
}

键盘事件处理

Page 模式支持按键控制,通过实现 egui_port_hanlde_key_event 接口将按键事件分发给当前 Page:

void egui_port_hanlde_key_event(int key, int event)
{
    if (event == 0)
        return;

    if (current_page)
    {
        egui_page_base_key_pressed(current_page, key);
    }
}

egui_page_base_t 内置了 key_pressed 回调支持,各 Page 可自行处理按键逻辑。

与 Activity 模式对比

特性

Activity 模式

Page 模式

生命周期

6 个状态(完整)

2 个状态(简化)

页面栈

支持多层栈管理

无栈,手动管理

切换动画

内置滑动动画支持

无内置动画

内存占用

每个 Activity 独立内存

union 共享内存

RAM 开销

所有 Activity 之和

最大 Page 的大小

Dialog 支持

内置

适用场景

复杂交互、多层导航

简单切换、资源受限

选型建议:

  • RAM 充裕(>4KB 可用于 UI)且需要页面栈、切换动画 -> Activity

  • RAM 紧张(<2KB 可用于 UI)或只需简单的页面切换 -> Page

HelloEasyPage 完整流程

example/HelloEasyPage/uicode_disp0.c 展示了 Page 模式的完整用法:

void uicode_disp0_init(egui_core_t *core)
{
    // 初始化 Toast
    egui_toast_std_init((egui_toast_t *)&toast, core);
    egui_toast_set_as_default((egui_toast_t *)&toast);

    // 启动第一个 Page
    index = 0;
    uicode_switch_page(0);
}

整个应用只需要一个 union page_array 的内存,加上一个 current_page 指针和一个 index 变量,即可管理任意数量的页面。

相关文件

  • src/app/egui_page_base.h - Page 基类定义

  • example/HelloEasyPage/ - 完整示例

  • example/HelloEasyPage/egui_page_0.h/c - Page 0 实现

  • example/HelloEasyPage/egui_page_1.h/c - Page 1 实现

  • example/HelloEasyPage/egui_page_2.h/c - Page 2 实现