
前言:
之前同事WYongW寫了一篇《用Flutter寫一個(gè)簡單頁面》,本篇將和大家一起調(diào)研一下蘋果今年推出的SwiftUI框架。
接下來,讓我們一起入門一下SwiftUI(嘗嘗鮮)。
一、SwiftUI是什么?
1. 定義:
簡單來說,SwiftUI是蘋果在“WWDC-2019”推出的一款全新的“聲明式UI”框架。
拆開看,Swift + UI。(由此可以看出Swift越來越重要)
2. 特點(diǎn):
“簡潔迅速”的Swift:越來越簡潔的
Swift語法,配上Swift迅速的優(yōu)勢。“即視”的UI:降低調(diào)試成本,一邊寫
code、一邊就可查看UI。跨平臺(tái):一套代碼,即可完成
iOS、iPadOS、macOS、watchOS的開發(fā)與適配。

- “聲明式”編程:
簡單來說,對(duì)比之前的“指令式”編程,我們通常需要告訴計(jì)算機(jī)“怎么做”?
而“聲明式”編程是讓我們告訴計(jì)算機(jī)“做什么”?(至于最底層怎么做,我們無需關(guān)心。)
舉個(gè)例子,對(duì)于寫UI而言,
- 指令式編程:就是,怎么畫?把每個(gè)
frame、layout等等統(tǒng)統(tǒng)需要計(jì)算到位。 - 聲明式編程:就是,畫什么?把想要的效果描述出來,其他都交給框架去做。
3. 開發(fā)環(huán)境:
這么新的技術(shù)肯定需要環(huán)境的支持。SwiftUI所需要的開發(fā)環(huán)境,如下:
- Xcode:
Xcode 11.1+。 - MacOS:
MacOS 10.15+。 - iOS:
iOS 13+。
PS:由于
SwiftUI只能應(yīng)用與iOS 13系統(tǒng)以上的設(shè)備。
因此,這項(xiàng)技術(shù)不建議用在需要適配低版本(iOS 13以下)的App上。
不過如果是無需適配低版本的新項(xiàng)目,或者學(xué)習(xí)者全可以上手“玩一玩”。
畢竟蘋果的新技術(shù)還是很有意思的嘛~
二、SwiftUI的基本組件(語法)
這塊知識(shí)比較“基礎(chǔ)”且“重要”。只有記住了這些基本組件,我們才能用較少的代碼開發(fā)出精美的App。
下面,我將給大家介紹一些重要的SwiftUI組件:
組件介紹:
| 名稱 | 含義 |
|---|---|
| Text | 用來顯示文本的組件,類似UIKit中的UILabel。 |
| Image | 用來展示圖片的組件,類似UIKit中的UIImageView。 |
| Button | 用于可點(diǎn)擊的按鈕組件,類似UIKit中的UIButton。 |
| List | 用來展示列表的組件,類似UIKit中的UITableView。 |
| ScrollView | 用來支持滑動(dòng)的組件,類似UIKit中的UIScrollView。 |
| Spacer | 一個(gè)靈活的空間,用來填充空白的組件。 |
| Divider | 一條分割線,用來劃分區(qū)域的組件。 |
| VStack | 將子視圖按“豎直方向”排列布局。(Vertical stack) |
| HStack | 將子視圖按“水平方向”排列布局。(Horizontal stack) |
| ZStack | 將子視圖按“兩軸方向均對(duì)齊”布局(居中,有重疊效果) |
基本組件:
- Text:用來顯示文本的組件,類似UIKit中的
UILabel。
Text("Hello, we are QiShare!").foregroundColor(.blue).font(.system(size: 32.0))
- Image:用來展示圖片的組件,類似UIKit中的
UIImageView。
Image.init(systemName: "star.fill").foregroundColor(.yellow)
- Button:用于可點(diǎn)擊的按鈕組件,類似UIKit中的
UIButton。
Button(action: { self.showingProfile.toggle() }) {
Image(systemName: "paperplane.fill")
.imageScale(.large)
.accessibility(label: Text("Right"))
.padding()
}
- List:用來展示列表的組件,類似UIKit中的
UITableView。
List(0..<5){_ in
NavigationLink.init(destination: VStack(alignment:.center){
Image.init(systemName: "\(item+1).square.fill").foregroundColor(.green)
Text("詳情界面\(item + 1)").font(.system(size: 16))
}) {
//ListRow
}
ScrollView:用來支持滑動(dòng)的組件,類似UIKit中的
UIScrollView。Spacer:一個(gè)靈活的空間,用來填充空白的組件。
Divider:一條分割線,用來劃分區(qū)域的組件。
布局組件:
VStack:將子視圖按“豎直方向”布局。(Vertical stack)
HStack:將子視圖按“水平方向”布局。(Horizontal stack)
ZStack:將子視圖按“兩軸方向均對(duì)齊”布局。
功能組件:
NavigationView:負(fù)責(zé)App中導(dǎo)航功能的組件,類似UIKit中的
UINavigationView。NavigationLink:負(fù)責(zé)App頁面跳轉(zhuǎn)的組件,類似于
UINavigationView中的push與pop功能。
NavigationView {
List(0..<5){_ in
NavigationLink.init(destination: VStack(alignment:.center){
Image.init(systemName: "\(item+1).square.fill").foregroundColor(.green)
Text("詳情界面\(item + 1)").font(.system(size: 16))
}) {
//ListRow
}
}
.navigationBarTitle("導(dǎo)航\(item)",displayMode: .inline)
- TabView:負(fù)責(zé)App中的標(biāo)簽頁功能的組件,類似UIKit中的
UITabBarController。
TabView {
Text("The First Tab")
.tabItem {
Image(systemName: "1.square.fill")
Text("First")
}
Text("Another Tab")
.tabItem {
Image(systemName: "2.square.fill")
Text("Second")
}
Text("The Last Tab")
.tabItem {
Image(systemName: "3.square.fill")
Text("Third")
}
}
.font(.headline)
三、SwiftUI快速上手實(shí)踐
下面讓我們快速實(shí)現(xiàn)一個(gè)有TabView、NavigationView、List的Demo。

SF Symbols 是從 iOS 13 和 macOS 10.15 開始內(nèi)置于系統(tǒng)中的字符圖標(biāo)庫,它提供了上千種常見的線條圖標(biāo),而且我們可以任意地為它們?cè)O(shè)置尺寸,顏色等屬性。Apple 甚至準(zhǔn)備了專門的app:SF Symbols 來幫助你查看可用的符號(hào):
接下來就讓我們用這些Symbols制作個(gè)小Demo。
- ContentView:
import SwiftUI
struct ContentView: View {
@State var isLeftNav = false
@State var isRightNav = false
init() {
//修改導(dǎo)航欄文字顏色
UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.systemBlue]
UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.systemBlue]
UINavigationBar.appearance().tintColor = .systemBlue
}
var body: some View {
TabView {
// Tab1:
NavigationView {
List(Symbols, id:\.self) {
ListRow(symbol: $0)
}
.navigationBarTitle(Text("SF Symbols"))
.navigationBarItems(leading: leftNavButton, trailing: rightNavButton)
}.tabItem {
Image.init(systemName: "star.fill")
Text("Tab1").font(.subheadline)
}
// Tab2:
NavigationView {
Text("This is the second tab.")
}.tabItem {
Image.init(systemName: "star.fill")
Text("Tab2").font(.subheadline)
}
}
}
var leftNavButton: some View {
Button(action: { self.isLeftNav.toggle() }) {
Image(systemName: "person.crop.circle")
.imageScale(.large)
.accessibility(label: Text("Left"))
.padding()
}
.sheet(isPresented: $isLeftNav) {
VStack {
Text("Hello, we are QiShare!").foregroundColor(.blue).font(.system(size: 32.0))
HStack {
Spacer()
Spacer()
Text("an iOS Team. ").fontWeight(.black).foregroundColor(.purple)
Spacer()
Text("We are learning SwiftUI.").foregroundColor(.blue)
Spacer()
}
}
}
}
var rightNavButton: some View {
Button(action: { self.isRightNav.toggle() }) {
Image(systemName: "paperplane.fill")
.imageScale(.large)
.accessibility(label: Text("Right"))
.padding()
}
.sheet(isPresented: $isRightNav, onDismiss: {
print("dissmiss RrightNav")
}) {
ZStack {
Text("This is the Right Navi Button.")
}
}
}
}
- ListRow:List對(duì)應(yīng)的Cell
struct ListRow: View {
var symbol: String
var body: some View {
NavigationLink(destination: ListDetail(symbol: symbol)) {
HStack {
//圖片
Image(systemName: symbol)
.resizable()
.frame(width: 60, height: 60)
.foregroundColor(Colors.randomElement())
//分割
Divider()
Spacer()
//文字
Text(symbol)
Spacer()
}
}
}
}
- ListDetail:
import SwiftUI
struct ListDetail: View {
var symbol: String
var body: some View {
VStack {
Text("Image:").font(.headline)
Spacer()
Image(systemName: symbol)
.foregroundColor(Colors.randomElement())
.imageScale(.large)
.scaleEffect(3)
.padding(.bottom, 100)
Divider()
Text("Image Name:").font(.headline)
Spacer()
Text(symbol)
.font(.largeTitle)
Spacer()
}
.navigationBarTitle(symbol)
}
}
源碼:本文Demo