初探 SwiftUI

Sunny Cheng
9 min readJul 13, 2020

--

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) { }

有三種方式可瀏覽設定選項

程式碼中對元件按 “Command+滑鼠左鍵 Click”,叫出選單後選 “Show SwiftUI Inspector”
直接在預覽畫面對元件按“Command+滑鼠左鍵 Click”,叫出選單後選 “Show SwiftUI Inspector”
叫出右側 Attribute inspector 操作欄位

Stack

SwiftUI 沒有任何約束條件,取而代之的是 Stack 的概念,Stack 可調整 Spacing、Alignment、Padding 與 Frame,調整畫面時程式碼會有所連動改變,反之亦然,有異於 Storyboard 跟程式碼間的不連動。

var body : some View 只能返回一個物件,故有複數以上的 UI 元件皆需包進 Stack 裡。

Spacer 會利用 HStack 的所有空間來留下空格

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)

會將其他部分加在這張 view 上

結合視圖

Spacer

Spacer()是一個填空剩餘空間的隱形空間,在此程式碼中,它加在整個 VStack 的最下層,Spacer 會考慮整個 VStack 的長度減掉既有 UI 元件的總長度,沿著 Y 軸將剩餘空間皆列為 Spacer。此程式碼中 Spacer( ) 加在最下面,會將其他 UI 元件往上推,造成從畫面最頂端開始往下排列的效果。

若添加在 HStack 裡,看添加的位置,會從螢幕左右兩邊開始排列。

Padding

實際改變 UI 元件框的大小,若內容超出不會被壓縮或截斷,但會實際改變與其他元件的間距。

藍色框部分因 padding 而縮小的邊界

OffSet

對 UI 元件的內容產生偏移,但不影響 UI 元件框的大小,因此需注意多個元件的間距可能不如預期,需配合 Padding 一起使用。

第二與第三張用相同的 offSet,卻沒有得到相同的效果是因為框架未實際改變,若需要調整,則需要同步使用 padding 將淺藍色框壓縮
同步使用 padding 改變框大小,使圖能均勻重疊

製作清單,點選後開啟詳細頁且傳送資料。

List

要創造與 UIKit 相同的 TableView 效果,使用 List

Data

List 的數據皆需 identifiable,否則 List 無法辨識,另外可辨識的 ID 本身需服從 Hashable protocol,例如 String、Int 型別。

創造可供辨識的數據有兩種方法:

  1. 對每個數據結構加入唯一辨識碼,例如 UUID

2. 數據結構服從 Identifiable 協定,告訴 SwiftUI 此可供唯一辨識,即使用 List 不用再提供 id,數據本身已可被識別。

數據有 id 可供唯一辨識,因此無需再添加 id: \.id

List UI

有了資料後,產出可呈現資料的清單介面

  1. 製作清單的 row UI

2. 將每個 row UI 包進 List 裡

3. 製作 testData:[MovieData] 測試

Navigation

  1. 加入 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 改變時被觸發,得到改變後的狀態。

App protocol

一次呈現不同裝置的預覽畫面

若不想看整個手機顯示,也可以使用 .previewLayout(.sizeThatFits) 做最適呈現。

--

--

Sunny Cheng
Sunny Cheng

Written by Sunny Cheng

礦冶工程碩士,職涯第一個轉彎為新加坡市場的業務經理,自學後又轉彎成 OTT 產業的 iOS 工程師。

No responses yet