PixelUI 里的一个 App 是 IApplication 的派生类。ViewManager 负责构造、切换和销毁 App;App 本身负责画页面、处理没被 Widget 消耗的输入,并在生命周期回调中注册自己的 Widget 和回调。
1. 最小 App Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include "core/app/IApplication.h" #include "core/app/app_system.h" #include "widgets/text_button/text_button.h"
class HelloApp final : public IApplication { public: HelloApp(PixelUI& ui, void*) : ui_(ui), closeButton_(ui, 38, 36, 52, 16, "Back") {}
void onEnter(ExitCallback exitCallback) override { IApplication::onEnter(exitCallback);
closeButton_.setCallback([this]() { requestExit(); }); closeButton_.onLoad(); ui_.addWidgetToFocusManager(&closeButton_); ui_.markDirty(); }
void draw() override { U8G2& display = ui_.getU8G2(); display.setFont(u8g2_font_6x10_tf); display.drawStr(32, 20, "Hello PixelUI"); closeButton_.draw(); }
bool handleInput(InputEvent event) override { if (event == InputEvent::BACK) { requestExit(); return true; } return false; }
private: PixelUI& ui_; TextButton closeButton_; };
static const uint8_t hello_icon_bits[72] = {};
AppItem helloApp = AppItem::make<HelloApp>("Hello", hello_icon_bits);
|
AppItem::make<T>() 默认要求 T(PixelUI&, void*) 这个构造函数。第二个参数是非拥有的启动参数,不需要时可以忽略它。
2. 生命周期
| 回调 |
何时发生 |
适合做什么 |
| 构造函数 |
App 在 arena 中创建 |
构造成员,不要把 this/成员指针发布给 manager |
onEnter() |
App 成为顶层;如果有 fade,在 fade 完成后 |
设回调、调 onLoad()、注册 Widget,开始动画 |
onPause() |
另一个 App 压到它上面 |
暂停 App 自己管理的工作 |
onResume() |
上层 App 退出 |
恢复持续绘制等 App 级状态 |
onExit() |
离开页面栈,销毁前 |
撤销 App 自己管理的外部状态 |
| 析构函数 |
onExit() 后 |
释放 App 内部资源 |
IApplication::onEnter(exitCallback) 不能漏掉,否则 requestExit() 没有可调用的退出函数。
3. 输入路由
ui.handleInput(event) 的顺序大致是:
1
| PixelUI FocusManager -> active Popup -> top App
|
Widget 没有处理的事件才会落到 HelloApp::handleInput()。一般在这里处理 BACK 和属于整个页面的按键。
4. 注册和启动
1 2 3 4 5 6 7 8
| AppManager::getInstance().registerApp(helloApp);
ViewManager& views = *ui.getViewManagerPtr(); const auto result = views.launch(helloApp, nullptr);
if (result != ViewManager::LaunchResult::Ok) { show_launch_error(result); }
|
不需要出现在 launcher 中的页面可以用 views.push<HelloApp>(ui, nullptr) 直接启动。两种启动方式和失败结果见App 生命周期与 ViewManager。
5. 启动参数
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct HelloParameters { const char* message; };
class ParameterApp final : public IApplication { public: ParameterApp(PixelUI& ui, void* raw) : ui_(ui), params_(static_cast<HelloParameters*>(raw)) {}
private: PixelUI& ui_; HelloParameters* params_; };
|
parameters 没有类型信息,也不延长对象寿命。它和 getCurrentApp() 返回的都是非拥有指针;若 App 要继续保存启动参数,目标对象必须比 App 活得更久。不要传入函数即将返回的局部变量地址。更通用的规则见回调与对象生命周期。