初探 SwiftUI
Xcode11 版本(最低支援 macOS 10.14.4)開放撰寫 SwiftUI 框架,但若要即時看到預覽畫面,仍須將 macOS 版本升至 macOS 10.15 上。
SwiftUI好處是可支援 UI進階功能,如 Dark Mode、Localization、Accessibility 等,且可以支援所有的平台,包含 macOS、iOS、iPadOS、watchOS 及 tvOS。
若 Xcode 新建 SwiftUI 專案有預覽視窗卻無法顯示,得到 OSStatus error -10825 /* The app cannot run on the current OS version*/,注意是否左上角的 Deployment Target 誤選到 macOS。
設計 SwiftUI 畫面
Text = UILabel
List = UITableView
Toggle = UISwitch
Text.font / Text.foregroundColor / Text.multilineTextAlignment
Image.resizable( ).frame(width: height: alignment)
Stack(alignment: spacing) { }
有三種方式可瀏覽設定選項
Stack
SwiftUI 沒有任何約束條件,取而代之的是 Stack 的概念,Stack 可調整 Spacing、Alignment、Padding 與 Frame,調整畫面時程式碼會有所連動改變,反之亦然,有異於 Storyboard 跟程式碼間的不連動。
因 var body : some View 只能返回一個物件,故有複數以上的 UI 元件皆需包進 Stack 裡。
UI 元件內的佈局影響力會大於 Stack,例如 Stack Alignment 選 leading ,Text 元件選 Trailing,則排列會以 Trailing 優先。
結合UIKit 與 SwiftUI View
要完成以下視圖有三個部分,一個是 UIKit 底下的 MapView,以及兩個由 SwiftUI 所創造的 CircleImage 與 Stacks and text。
創造 MKMapView (MapView.swift)
UIKit 所製造出來的 view 須遵從UIViewRepresentable
協定方可被加入 SwiftUI 中,協定將會加入兩個 methods,makeUIView(context:)
與updateUIView(_:context:)
,分別建立與更新 MKMapView。
當預覽畫面在 static mode 會呈現一片空白是因為此模式下,只支持 SwiftUI 視圖,因MKMapView
為 UIView 的子類,故需切到 live mode 以查看地圖。
創造 CircleImage (CircleImage.swift)
創造 Stacks and text (ContentView.swift)
結合視圖
Spacer
Spacer()
是一個填空剩餘空間的隱形空間,在此程式碼中,它加在整個 VStack 的最下層,Spacer 會考慮整個 VStack 的長度減掉既有 UI 元件的總長度,沿著 Y 軸將剩餘空間皆列為 Spacer。此程式碼中 Spacer( ) 加在最下面,會將其他 UI 元件往上推,造成從畫面最頂端開始往下排列的效果。
若添加在 HStack 裡,看添加的位置,會從螢幕左右兩邊開始排列。
Padding
實際改變 UI 元件框的大小,若內容超出不會被壓縮或截斷,但會實際改變與其他元件的間距。
OffSet
對 UI 元件的內容產生偏移,但不影響 UI 元件框的大小,因此需注意多個元件的間距可能不如預期,需配合 Padding 一起使用。
製作清單,點選後開啟詳細頁且傳送資料。
List
要創造與 UIKit 相同的 TableView 效果,使用 List
Data
List 的數據皆需 identifiable,否則 List 無法辨識,另外可辨識的 ID 本身需服從 Hashable protocol,例如 String、Int 型別。
創造可供辨識的數據有兩種方法:
- 對每個數據結構加入唯一辨識碼,例如 UUID
2. 數據結構服從 Identifiable 協定,告訴 SwiftUI 此可供唯一辨識,即使用 List 不用再提供 id,數據本身已可被識別。
List UI
有了資料後,產出可呈現資料的清單介面
- 製作清單的 row UI
2. 將每個 row UI 包進 List 裡
3. 製作 testData:[MovieData] 測試
Navigation
- 加入
NavigationView
包住 List,使得清單內的欄位可有被點選的行為
2. 製作點選後的目標頁面
3. 使用 NavigationLink
決定被點選的欄位及點選後的目標頁面 (destination),若被點選的 UI 沒有用 List 包裹,則會將整個 View 視為單一可被點選的畫面。另外在清單加上 .navigationBarTitle
新增導覽標題。
App Life Cycle
要呈現 SwiftUI 所做出的 view 時,需將 view 包進 UIHostingController
裡,並指定給 window.rootViewController。
但在 Xcode12 beta 中,創建 SwiftUI 專案時,SceneDelegate 與 AppDelegate 可被 <AppName>App.swift 檔取代 ( iOS14+),取決於創建專案時所指定的 Life Cycle。
@main 為標誌 App 的進入點,在 App 開啟時會被喚起。若要得到 App 的狀態,使用 “\” 拿到 Key Path 存入 scenePhase 參數裡,onChange 會在 scenePhase 改變時被觸發,得到改變後的狀態。
一次呈現不同裝置的預覽畫面
若不想看整個手機顯示,也可以使用 .previewLayout(.sizeThatFits) 做最適呈現。