iT邦幫忙

2024 iThome 鐵人賽

DAY 28
1
Security

Flipper Zero 宇宙最強攻略:30 天帶你從入門到入坑系列 第 28

Day28 - 會寫完喔!倒數 48 小時的勝利宣言,即將踏上終點的鐵人賽之旅!

  • 分享至 

  • xImage
  •  

Cover

cover
圖片來源:https://artprojectsforkids.org/how-to-draw-a-dolphin/

資安倫理宣導

請注意,透過 Flipper Zero 學習的資訊技術與知識,目的在於提升個人的技術能力和資安意識。我們強烈呼籲大家,絕對不要使用所學知識從事任何違法行為。您的合法使用是我們的期望,也是您自身責任的
一部分。

開發倒數 48 小時

SceneManager and ViewDispatcher

我們要繼續提到 SceneManager 透過一系列的 scene_manager_* 開頭的函式來管理應用程式中的所有場景細節。主要是確保當進入場景、離開場景或接收到新事件時,相關的處理函式會被正確的呼叫。
另一個是 ViewDispatcher 是使用許多 view_dispatcher_* 的函式來管理 views。這些函式會在 SceneManager 中被呼叫。總之,ViewDispatcher 是負責處理場景中 Views 的顯示和管理。
當我們在定義應用程式場景時,應提供所有場景處理函式作為一個 SceneManagerHandlers 結構傳給 scene_manager_alloc 函式。例如說作者這邊的場景會用數字做為索引,同時為了方便追蹤這些場景,通常我們會定義一個 enum 類型來表示場景的索引,像是:

typedef enum {
    TestAppScene_MainMenu,      // 主選單場景
    TestAppScene_FirstPopup,    // 第一個彈出視窗場景
    TestAppScene_SecondPopup,   // 第二個彈出視窗場景
    TestAppScene_count          // 場景計數,方便後續擴展
} TestAppScene;

像是這邊的 count 只要放在枚舉的最後一項,之後增加或是修改場景數量的時候都可以輕鬆算出場景的總數。

而視圖是可以重複使用的,因此應用程式中可能場景數量會比視圖更多。換句話說,我們有可能一個視圖對應多個場景:

typedef enum {
    TestAppView_Menu,   // 菜單視圖
    TestAppView_Popup   // 彈出視圖
} TestAppScene;

這樣也提高了資源利用率。

初始化應用程式

首先我們會在 test_app_init 函式裡面初始化 scene manager 以及 view dispatcher:

TestApp* app = malloc(sizeof(TestApp));
test_app_scene_manager_init(app);
test_app_view_dispatcher_init(app);

設定 Scene Manager

app->scene_manager = scene_manager_alloc(&test_app_scene_event_handlers, app);

我們為 SceneManager 分配記憶體。
其中這邊的第二個參數是 context,當場景處理方法被調用時,會回傳這個 context,第一個參數是 SceneManagerHandlers* test_app_scene_event_handlers 已經提前定義好並包含 on_enteron_exiton_event 處理函式集合。

處理函式集合

on_enter_handlers:當進入某個場景時會調用這個處理函式集合,它包含了所有場景的進入處理邏輯。這些函式與定義的 enum 順序一致。例如,進入主選單或彈出視窗時會調用對應的進入函數。

void (*const test_app_scene_on_enter_handlers[])(void*) = {
    test_app_scene_on_enter_main_menu,
    test_app_scene_on_enter_popup_one,
    test_app_scene_on_enter_popup_two};

on_event_handlers:當某個場景處於活動狀態時,並且收到了事件(如使用者操作),會調用這個事件處理函式集合。每個場景有其專屬的事件處理邏輯,也是與 enum 順序一致。

bool (*const test_app_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
    test_app_scene_on_event_main_menu,
    test_app_scene_on_event_popup_one,
    test_app_scene_on_event_popup_two};

on_exit_handlers:當離開某個場景時,會調用這個處理函式集合。這些函式負責處理場景退出時的清理或其他工作,同樣是與 enum 順序保持一致。

void (*const test_app_scene_on_exit_handlers[])(void*) = {
    test_app_scene_on_exit_main_menu,
    test_app_scene_on_exit_popup_one,
    test_app_scene_on_exit_popup_two};

test_app_scene_event_handlers:這是所有場景處理器的集合,包含 on_enteron_eventon_exit 的處理函數。這樣的結構可以確保每個場景的進入、事件處理和退出邏輯都能正確運行。

const SceneManagerHandlers test_app_scene_event_handlers = {
    .on_enter_handlers = test_app_scene_on_enter_handlers,   // 進入處理函式集合
    .on_event_handlers = test_app_scene_on_event_handlers,   // 事件處理函式集合
    .on_exit_handlers = test_app_scene_on_exit_handlers,     // 退出處理函式集合
    .scene_num = TestAppScene_count};                       // 場景數量

設定 View Dispatcher

test_app_view_dispatcher_init 函式負責初始化視圖分發器,這部分稍微複雜一點。具體的步驟如下:

  1. 首先我們要先分配一個視圖分發器,用來管理應用程式中的不同視圖:
app->view_dispatcher = view_dispatcher_alloc();
  1. 接著,我們需要啟用隊列功能,讓視圖分發器能夠依序處理事件。
view_dispatcher_enable_queue(app->view_dispatcher);
  1. 然後我們需要為應用程式中的各個視圖分配記憶體,這裡我們分別為菜單和彈出視窗進行分配:
app->menu = menu_alloc();
app->popup = popup_alloc();
  1. 接著我們將事件從視圖傳遞到場景管理器,因為視圖本身會處理事件和導航功能,但我們希望這些事件能夠傳遞到場景管理器,使得目前處於活躍狀態的場景能夠接收到並處理這些事件。因此我們需要設置事件回調函式來將事件傳遞到場景管理器。
// 設置回調函式,將事件從視圖傳遞到場景管理器
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
    app->view_dispatcher,
    test_app_scene_manager_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
    app->view_dispatcher,
    test_app_scene_manager_navigation_event_callback);
  1. 最後,我們需要將視圖註冊到視圖分發器,並且將它們與各自的列舉值進行對應。這樣,當我們需要切換到特定視圖時,系統能夠正確處理視圖之間的切換。
// 將視圖添加到分發器,並根據它們的列舉值進行索引
view_dispatcher_add_view(
    app->view_dispatcher,
    TestAppView_Menu,
    menu_get_view(app->menu));

view_dispatcher_add_view(
    app->view_dispatcher,
    TestAppView_Popup,
    popup_get_view(app->popup));

按讚訂閱收藏小鈴噹叮叮叮

今天就先到這邊,預計明天走完教學,後天做出自已的 app。
各位明天見!

References


上一篇
Day27 - 死線逼近!強制切回生存模式的 72 小時開發極限挑戰!
下一篇
Day29 - 絶対的な優位を掌握せよ!倒数24時間、登場する圧軸必殺技!
系列文
Flipper Zero 宇宙最強攻略:30 天帶你從入門到入坑30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言