第 1 章
SwiftUI 的介紹

2019 年的 WWDC,Apple 宣布了一個全新的框架(Framework ),稱為「SwiftUI」, 這讓所有的開發者都大為驚訝。這不只改變了開發 iOS App 的方式,也是自從 Swift 問世以來,Apple 開發者的生態系統(包括iPadOS、macOS、tvOS 與 watchOS)的最大轉變。

SwiftUI 以一種創新且極度簡單的方式,透過 Swift 的力量,讓使用者建立橫跨所有 Apple 平台的使用者介面。只要一套工具與 API,即能建立適用所有 Apple 裝置的使用者介面。

- Apple (https://developer.apple.com/xcode/swiftui/)

開發者已經對於「應該使用故事板(Storyboard )或是以程式化的方式來建立 App UI」一事爭論已久,而 SwiftUI 的導入,即是Apple 對這個問題的解答。有了這個全新的框架, Apple 提供開發者一個建立使用者介面的新方式。請參見圖 1.1,並看一下它的程式。

圖 1.1 SwiftUI 的程式
圖 1.1 SwiftUI 的程式

自 SwiftUI 推出之後,你可以使用宣告式(Declarative )的 Swift 語法來開發 App 的 UI,這表示這個 UI 程式的語法更容易且自然。和目前的UI 框架做比較,如 UIKit,你可以使用較少的程式碼來建立相同的UI。

預覽功能一直是 Xcode 的弱點,雖然你可以在介面建構器( Interface Builder )預覽簡單的佈局,不過通常無法預覽完整的 UI,除非 App 被載入模擬器( Simulator )才行。有了 SwiftUI,一邊寫程式,一邊就可以立即看到 UI 的成果。舉例而言,你在表格中加入一筆新紀錄,Xcode 會立即在預覽畫布(Preview Canvas)上渲染(Render)UI 的改變結果。如果你想在深色模式(dark mode)預覽你的 UI,你只要變更一個選項即可,這個即時預覽功能讓 UI 的開發更加容易,且更新的速度更快。

不只可以預覽 UI,新的畫布也可以讓你使用視覺拖曳的方式來設計使用者介面。最棒的是,當你以視覺方式加入UI 元件時,Xcode 會自動地產生 SwiftUI 程式。程式與UI 總是同步的,這是 Apple 開發者期待以久的功能。

在本書中,你將會深入 SwiftUI,學習如何佈局內建元件,並以這個框架建立複雜的 UI。我知道你們之中已經有iOS 開發經驗,讓我先來告知你,目前你所使用的框架(如UIKit)與 SwiftUI 的主要差異性。如果你完全是一個新的 iOS 開發者,甚至沒有任何程式經驗,你可以先將這作為參考,或者跳過 1.1 小節,我不想要因此而讓你遠離SwiftUI, 因為對於初學者來說,這是一個非常棒的框架。

宣告式程式設計與指令式程式設計

和Java、C++、PHP 與 C# 一樣, 自從 Swift 釋出以來, 一直是一個指令式程式( Imperative Programming )語言。不過,SwiftUI 很自豪的聲稱是一個宣告式 UI 框架( Declarative UI Framework ),可以讓開發者以宣告式的方式來建立 UI。但是這個「宣告式」(declarative )的意思是什麼呢?又和指令式程式設計有何不同?更重要的是,這會對你寫程式的方式有什麼改變?

如果你才剛開始學習程式。你可能不需要去管這之間的差異為何,因為對你來說,一切都是新的內容。不過,如果你有些物件導向的程式經驗,或之前曾以 UIKit 開發過,這個轉變模式影響了你如何建立使用者介面的思考方式。你可能需要忘記一些舊思維來學習新觀念。

那麼,指令式程式設計與宣告式程式設計的不同之處為何呢?如果你至維基百科搜尋這兩個專有名詞,你會找到這些定義:

在電腦科學中,指令式程式設計是一種使用了敘述語句來變更程式狀態的程式設計典範(Programming Paradigm )。就像在自然語言中表達祈使句指令一樣的方式。指令式程式設計包含了許多讓電腦能夠執行的指令。

在電腦科學中,宣告式程式設計是一種建構電腦程式的結構與元件風格的程式設計典範,沒有敘述控制流程來表達運算邏輯。

如果你沒有學過電腦科學的話,非常難了解其中的差異性。讓我以不同的方式來做解釋。

這裡不將重點放在程式設計,我們來談一下披薩的烹飪(或任何你喜歡的料理)。假設你要求你的幫手去準備一個披薩,你可以使用指令式或者宣告式的方式來做。要以指令式烹飪披薩,你需要很清楚地告訴你的幫手每一個指示,就像食譜一樣:

  1. 加熱到 550 ℉或更高,至少要 30 分鐘。
  2. 準備一磅麵團。
  3. 將麵團揉成 10 英吋大小的圓。
  4. 將蕃茄醬以湯匙舀入披薩的中間,並均勻塗抹至邊緣。
  5. 再撒上一些配料(包括洋蔥、切片蘑菇、義式辣肉腸( pepperoni)、煮過的香腸、煮過的培根、切細的辣椒)與起司。
  6. 將披薩烘烤 5 分鐘。

此外,如果你是以宣告式的方式,你不需要訂定所有的步驟,只要描述你想要做什麼樣的披薩,厚皮或者薄皮?要義式辣肉腸與培根,或只是經典的瑪格莉特( margherita ) 加上番茄醬?10 吋或者16 吋?這個幫手將會處理剩下的事,並為你烘烤披薩。

這是指令式與宣告式的主要不同之處。現在回到 UI 程式,指令式 UI 程式設計需要開發者寫下細節的指示,來佈局 UI 以及控制其狀態。反之,宣告式UI 程式設計讓開發者描述 UI 的樣貌,以及狀態改變時你要它能做什麼。

宣告式的程式風格可以讓程式更容易閱讀與理解。更重要的是,SwiftUI 框架可以讓你以很少的程式碼,來建立一個使用者介面。例如:你準備要在 App 中建立一個心形按鈕, 這個按鈕應該放置於螢幕中心,並且能夠偵測觸控事件,當使用者點擊這個心形按鈕時, 它的顏色會從紅色變為黃色,而當使用者按下這個心形不放時,它會以動畫形式放大。

圖 1.2. 心形互動按鈕的實作
圖 1.2. 心形互動按鈕的實作

參考一下圖 1.2,此為實作心形按鈕所需要的程式,大約 20 行的程式,你就可以建立一個互動式按鈕,並加上一個縮放動畫,而這就是宣告式 UI 框架的威力之處。

不再是介面建構器與自動佈局

在 Xcode 11 以上版本,你可以選取 SwiftUI 與 Storyboard 來建構使用者介面,如圖 1.3 所示。如果你之前已建立過App,你可能使用介面建構器在故事板上佈局 UI,但是有了 SwiftUI, 介面建構器與故事板則完全消失。它會被程式編輯器與預覽畫布所取代,如圖 1.2 所示。你需要將程式寫在程式編輯器,然後 Xcode 會即時渲染使用者介面,並將其顯示在畫布中。

圖 1.3. 在 Xcode 中的使用者介面選項
圖 1.3. 在 Xcode 中的使用者介面選項

「自動佈局」( Auto Layout)一直是學習iOS 開發中的一個困難的主題。有了 SwiftUI, 你不再需要學習如何定義一個佈局約束條件,並解決佈局的衝突問題。現在只要使用堆疊( Stack )、間隔( Spacer )與間距( Padding ),來組成想設計的UI 即可。我們將在後面的章節討論這些觀念。

Combine 方法

除了故事板之外,視圖控制器( View Controller )也不見了。對於新手,你可以忽略什麼是視圖控制器。若你是有經驗的開發者,你會發現一件奇怪的事,即 SwiftUI 沒有使用一個視圖控制器來當作一個中心建構區塊,以作為視圖與模型間的溝通。

視圖之間的溝通與資料分享,現在是透過另外一個稱為「Combine」(合併)的新框架來進行。這個新的方法完全取代了在UIKit 中視圖控制器的角色。在本書中,我們將會說明 Combine 的基本觀念,學習如何使用它來處理UI 事件。

學一次到處適用

雖然本書將重點放在 iOS UI 的建立,但你在這裡所學到的內容,也可以應用在其他 Apple 平台,例如:watchOS。在 SwiftUI 推出之前,你需要使用平台特定的 UI 框架來開發使用者介面,例如:使用 AppKit 來撰寫macOS App 的 UI;要開發 tvOS App,則依賴 TVUIKit;而開發 watchOS App,則是使用 WatchKit。

SwiftUI 推出之後,Apple 提供開發者一個統一的 UI 框架,來建立所有 Apple 裝置的使用者介面。為 iOS 所撰寫的UI 程式碼,可以輕易地移植到你的 watchOS/macOS/watchOS App,而不需要修改,或只要做小幅度的修正即可,這要歸功於「宣告式 UI 框架」。

使用者介面的程式敘述如下。依照平台,在 SwiftUI 中的同一段程式,可以產生不同的 UI 控制。舉例而言,以下這段程式為宣告一個切換開關:

Toggle(isOn: $isOn) {
    Text("Wifi")
        .font(.system(.title))
        .bold()
}.padding()

對於 iOS 與 iPadOS,Toggle 會渲染為開關。而 macOS ,SwiftUI 會將這個控制元件(control )渲染為核取方塊樣式,如圖1.4 所示。

圖 1.4. macOS 與iOS 的切換開關
圖 1.4. macOS 與iOS 的切換開關

這個統一框架的美妙之處,即是你可以針對所有 Apple 平台重複使用大部分的程式,而無需變更。SwiftUI 協助渲染對應的控制與佈局等這些繁重的工作。

不過,不要認為 SwiftUI 是一個「寫一次,到處可以執行」的解決方案。如同Apple 在 WWDC 所強調的,這不是SwiftUI 的目標。因此,不要期望你可以完美地將美麗的 iOS App 轉換成 tvOS App,而不需要做任何的修改。

只要是合適的地方,一定是有機會共享相同的程式碼。重要的是,我們不能將 SwiftUI 想成寫一次,到處執行,而是學習一次,到處適用。

- WWDC 講座(SwiftUI 於所有裝置)

雖然 UI 程式是可以跨平台,對於特定類型的裝置,你依然需要提供對應的規格。你應該要常常檢視你的 App 的每一個版本,以確保對某個平台是正確的。這麼說好了, SwiftUI 已經省下了你學習另外一個平台專用框架的許多時間,而且你可以重用大部分的程式碼。

UIKit/AppKit/WatchKit 的介接

我可以在我目前的專案中使用 SwiftUI 嗎?我不想要重寫整個以 UIKit 所建立的 App。

SwiftUI 可以設計用於目前的框架如 iOS 的 UIKit 與 macOS 的 Appkit。為了能夠將視圖或控制器加入 SwiftUI 中,Apple 提供幾個代表性(representable)的協定供你採用,如圖 1.5 所示。

圖 1.5. 目前 UI 框架的代表性協定
圖 1.5. 目前 UI 框架的代表性協定

例如:若你有一個自訂的視圖是使用 UIKit 開發,你可以採用 UIViewRepresentable 協定,來讓它相容 SwiftUI。圖 1.6 是在 SwiftUI 中使用 WKWebView 的範例程式。

圖 1.6. 移植 WKWebView 至 SwiftUI
圖 1.6. 移植 WKWebView 至 SwiftUI

下一個專案改採SwiftUI 吧

每當一個新框架釋出後,通常就會有人問:「這個框架是否可以用在我下一個專案中,是否應再觀望一些時間?」

雖然 SwiftUI 對大部分開發者而言依然是全新的,這也正是學習並整合這個框架進入你的新專案的好時機。隨著 Xcode 14 釋出,經過 Apple 改版後的 SwiftUI 框架已經更加穩定,功能也更多。如果你有一些個人的專案或者是你的公司一些業餘專案( Side Project )在進行,我想沒有什麼理由不嘗試一下 SwiftUI。

必須這樣說,你需要仔細考慮是否要在你的商業性專案中應用SwiftUI。SwiftUI 的一個主要缺點是只能在運行 iOS 13、macOS 10.15、tvOS 13 與 watchOS 6 版本以上的裝置才能執行。如果你的 App 仍需要支援比較舊版本(例如 iOS 12)的平台,這種情況下,可能需要等待一下,再來採用 SwiftUI。

在撰寫本書時,SwiftUI 已經超過三年,Xcode 14 已經為 SwiftUI 增加了更多的 UI 控制與新的 API(例如 Charts),就功能而言,你無法和目前釋出多年的UI 框架(如 UIKit )相比。一些功能(例如:使用照相機)很明顯就只有舊框架有,而無法在 SwiftUI 取得,你可能需要開發一些解決方案來處理這些問題。在已經上市的產品採用 SwiftUI,需要再多做一點考量。

無疑的,SwiftUI 還是很新的,需要一些時間才能變成一個成熟的框架,但很明確的, SwiftUI 是 Apple 平台應用程式開發的未來,即使目前可能還無法應用在你的專案中。建議可從一些業餘的產品來開始嘗試,並摸索這個框架,當你更加熟練之後,你將會喜愛以宣告式來開發 UI。


想更深入學習SwiftUI和下載完整程式碼?你可以從 AppCoda網站購買《精通 SwiftUI》完整電子版。

results matching ""

    No results matching ""