SwiftUI 小技巧:在 iOS 13 實作 Context Menu 加強與設備的互動!


較早之前,Apple 正式發佈了 iOS 13。當中除了深色模式 (Dark mode) 和其他新功能外,最新版本的 iOS 還展示了一種與設備互動的新方法,就是 Context Menu

Context Menu 功能與 3D Touch 中的 Peek & Pop 類似。兩者其中一個最大的分別,就是此功能可在所有運行 iOS 13 及以上版本的設備上使用,即使該設備不支持 3D Touch 亦可。如果設備支援 3D Touch,大家就可以使用 Touch and Hold 手勢或 Force Touch,來顯示 Context Menu。

如果設備已升級到 iOS 13,你就可以在大多數內建 App 中找到這個新控件,例如「地圖」和「照片」。

在這篇教學中,讓我們一起看看如何在 SwiftUI 實作 Context Menu!

注意:你需要有 Xcode 11 和 macOS Catalina (v10.15),才能遵循本教程。

在 SwiftUI 構建 Context Menu

首先,請下載初始專案,並在 Mac 上解壓縮。打開 SwiftUIList.xcodeproj 檔案,並運行專案或在畫布 (canvas) 中預覽,App 應該會顯示一個餐廳列表。

swiftui-context-menu-starter
編者註:如果你是 SwiftUI 新手,不知道如何建構列表,可以參閱我們的 SwiftUI 初學者教程

我們要做的,就為這個範例 App 建立一個 Context。我們希望當使用者按住任何一行時,就可以觸發 Context Menu。在菜單中,它提供了兩個操作按鈕供使用者選擇 —— Delete 和 Favorite。如果使用者點擊 Delete 按鈕,該行就會從列表中被刪除;而如果使用者點擊 Favorite 按鈕,該行就會有星號標記。

使用 ContextMenu 修飾符

有了 SwiftUI,Context Menu 的實作就變得非常簡單!你需要做的就只是將 contextMenu 容器 (container) 附加到一個視圖上,並設置菜單選項。

要在 Context Menu 中顯示 Delete 和 Favorite 兩個選項,我們可以如此將 contextMenu 附加到列表中的每一行:

實作按鈕操作 (Button Action)

雖然到目前為止,我們尚未實作任何按鈕操作,但如果你執行 App,並接住其中一行時,App 已經會彈出 Context Menu。

context-menu-delete-favorite

現在,讓我們繼續實作 Delete 的刪除操作。與 onDelete 處置器 (handler) 不同,contextMenu 不會為我們提供所選餐廳的索引 (index)。要弄清楚,我們就需要做幾個步驟。先在 ContentView 中創建一個新函數:

這個 delete 函數會接收一個餐廳物件,並在 restaurants 陣列 (array) 中搜索其索引。為了找到索引,我們呼叫 firstIndex 函數,並指定搜索條件。該函數的作用就是搜索陣列,並將所選餐廳的 ID 與陣列中的 ID 進行比較。如果有匹配的 ID, firstIndex 函數就會回傳所選餐廳的索引。有了索引之後,我們就可以通過調用 remove(at:),將所選餐廳從 restaurants 陣列中刪除。

接下來,在 // delete the selected restaurant 下插入以下這行程式碼:

當使用者點選 Delete 按鈕時,我們只需要呼叫 delete 函數。

為了可以成功刪除該行,我們還需要使用 @State 關鍵字標記 restaurants 陣列:

現在,我們可以測試 App 了!點擊畫布中的 Play 按鈕以運行 App,按住其中一行以彈出 Context Menu。選擇 Delete,你應該會看到所選餐廳從列表中被刪除。

讓我們繼續實作 Favorite 按鈕。點擊此按鈕後,App 將在所選餐廳中放一顆星。Restaurant 結構已經有一個名為 isFavorite 的屬性 (property),這個屬性會表示餐廳是否被標記為喜歡 (Favourite)。在默認情況下,其值設置為 false

Delete 功能相似,我們將在 ContentView 中創建一個單獨的函數,來設置喜歡的餐廳。插入以下程式碼以創建新功能:

上面這段程式碼與 delete 函數非常相似。我們首先找出所選餐廳的索引,找到索引後,就可以更改其 isFavorite 屬性的值。在這裡,我們調用 toggle 函數來切換值。比如說,如果 isFavorite 的值原本是設置為 false,在調用 toggle() 之後,該值將更改為 true

接下來,我們需要處理行的 UI。每當餐廳的 isFavorite 屬性設置為 true時,該行應顯示一個星號指示符。像這樣更新 BasicImageRow 結構:

在上面的程式碼中,我們只在 HStack 中添加了一段程式碼。如果已選餐廳的 isFavorite 屬性設置為 true,我們就在該行添加一個間隔符 (spacer) 和一個系統圖像 (system image)。

這樣我們就完成 Favorite 功能的實作了!最後,將以下這行程式碼插入到 // mark the selected restaurant as favorite 下面,以調用 setFavorite 函數:

現在可以測試 App 了!在畫布上執行 App,按住其中一行(例如 Petite Oyster),然後選擇 Favorite。你應該會看到該行尾部出現了一個星號。

這樣我們就可以在 SwiftUI 中實作 Context Menu!希望你喜歡本篇教學文章。我們即將出版有關 SwiftUI 的新書,請繼續關注我們的資訊!

你可以在 GitHub 下載完整項目以作參考。

譯者簡介:Kelly Chan-AppCoda 編輯小姐。
原文SwiftUI Tip: How to Create a Context Menu in iOS 13

軟件工程師,AppCoda 創辦人。著有《iOS 10 App 程式設計實力超進化實戰攻略》、《iOS 9 App 程式設計實力超進化實戰攻略》、《養成iOS 8 App程式設計實力的25堂課》,以及《iOS 8 App程式設計進階實力的30項關鍵技巧》。曾任職於HSBC, FedEx等公司,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda,致力於iOS程式教學,產品設計及開發。

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This