Flipper Zero 宇宙最強攻略:30 天帶你從入門到入坑 Day28 - 會寫完喔!倒數 48 小時的勝利宣言,即將踏上終點的鐵人賽之旅!

kazma 成大資安社 創辦人/社長

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 類型來表示場景的索引,像是:

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

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

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

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

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

初始化應用程式

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

1
2
3
TestApp* app = malloc(sizeof(TestApp));
test_app_scene_manager_init(app);
test_app_view_dispatcher_init(app);

設定 Scene Manager

1
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 順序一致。例如,進入主選單或彈出視窗時會調用對應的進入函數。

1
2
3
4
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 順序一致。

1
2
3
4
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 順序保持一致。

1
2
3
4
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 的處理函數。這樣的結構可以確保每個場景的進入、事件處理和退出邏輯都能正確運行。

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

  • Title: Flipper Zero 宇宙最強攻略:30 天帶你從入門到入坑 Day28 - 會寫完喔!倒數 48 小時的勝利宣言,即將踏上終點的鐵人賽之旅!
  • Author: kazma
  • Created at : 2024-10-12 21:17:31
  • Updated at : 2024-10-27 17:34:56
  • Link: https://kazma.tw/2024/10/12/Flipper-Zero-宇宙最強攻略:30-天帶你從入門到入坑-Day28/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
Flipper Zero 宇宙最強攻略:30 天帶你從入門到入坑 Day28 - 會寫完喔!倒數 48 小時的勝利宣言,即將踏上終點的鐵人賽之旅!