SwiftUI基礎教程
SwiftUI只支援Xcode 11、iOS 13版本及以上。
官方文件連結:developer.apple.com/tutorials/s…
建立組合檢視
本篇文章將通過一個構建應用(Landmarks,一個可以發現、分享你喜歡地點的App)示例,來引導大家進行SwiftUI開發。我們將使用SwiftUI框架來構建Landmark詳情介面。
Landmarks利用stacks將圖片和文字組合起來來進行檢視佈局。你需要引用MapKit框架標頭檔案來建立一個地圖檢視。 你可以通過Xcode新的實時反饋功能,來優化你的檢視佈局 。
建立工程
利用SwiftUI應用模版來建立工程,然後探索瞭解下SwiftUI的畫布。
為了能夠體驗Xcode 11的view實時預覽和互動功能,一定要確保你的mac系統版本是macOS 10.15 beta。
第一步
開啟 Xcode->Create a new Xcode project,或者通過File > New > Project 來建立工程。
第二步
在模版選擇區域,選擇 iOS->Single View App->Next 。
第三步
輸入專案名稱 Landmarks->勾選Use SwiftUI->Next 儲存。
第四步
在Xcode導航欄,建立ContentView.swift。通常SwiftUI會宣告兩個結構體。第一個結構體繼承自View,並且在這兒進行View的佈局。第二個結構體宣告瞭一個ContentView
的preview,繼承自PreviewProvider。
感謝@SoolyChristina基友的友情提示。這兒並非是繼承的概念,原文的描述如下: The first structure conforms to the View protocol and describes the view’s content and layout. The second structure declares a preview for that view.
所以這兒宣告的兩個結構體,更像是遵循了View和PreviewProvider協議。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello World")
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
複製程式碼
第五步
在SwiftUI畫布中點選 Resume 進行檢視預覽。
Tip:如果畫布沒有展示出來,可以通過 Editor > Editor and Canvas 顯示出來。
第六步
把Hello World更改為Hello SwiftUI!
當你修改文案後,SwiftUI會自動更新檢視。(這他麼不就是熱過載嘛 Hot-Reload )
自定義Text View
你有兩種方式來自定義TextView。第一種方式是直接修改view程式碼,第二種方式是通過inspector檢查器來幫助你進行程式碼編寫。
當你構建Landmarks的時候,你可以運用任何一個編輯器來進行編碼工作:直接修改原始碼、通過畫布、通過inspector view檢查器。程式碼並不會關心你用什麼工具,它始終能夠保持最新狀態。
接下來,你將通過inspector來自定義Text View
第一步
在preview畫布上,按住Command鍵+點按Text文字框,這時候inspector就會被喚起。
inspector彈出框所展示的屬性也會因為不同的UI控制元件而有所不同。
第二步
通過inspector檢查器修改Text文字框的屬性。
第三步
修改文字框字型。
修改文字框字型是利用的系統的字型。
第四步
手動修改程式碼,即新增.color(.green) 把文字修改成綠色。
要自定義SwiftUI檢視,你可以呼叫modifiers方法。Modifiers可以修改檢視的屬性,並且modifier返回一個新的檢視,所以通常會將多個modifiers像鏈一樣垂直堆疊在一起。( 說白了就是鏈式程式設計,每呼叫一個方法就返回自身 )。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Turtle Rock")
.font(.title)
.color(.green)
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
複製程式碼
你編寫的程式碼肯定和view是一一對應的。當你通過inspector修改了view屬性之後,Xcode會自動更新你的程式碼。
第五步
這時候,開啟inspector,然後把文字Color屬性修改為Inherited。
第六步
注意一點的就是,Xcode會根據inspector修改自動更新你的程式碼。
利用Stacks組合檢視
我們建立了一個文字框用來顯示landmark的詳情資訊,並且把這個文字控制元件放到頭部。
當我們建立SwiftUI檢視控制元件的時候,我們會把控制元件的內容、佈局還有一些行為放在body屬性中;然而body屬性只返回了一個view。你可以利用stacks嵌入多個view,它可以垂直嵌入、水平嵌入等。
在這個篇幅,我們將使用垂直stack來顯示park詳情資訊。
第一步
Command+點按text初始化方法區域。選擇 Embed in VStack 。
第二步
接下來,我們將拖拽一個text view到stack中。
點選+號,開啟Library皮膚。拖拽一個text view到 “Turtle Rock”後面 。
第三步
修改text view文案為 Joshua Tree National Park 。
第四步
設定text view的字型。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("Turtle Rock")
.font(.title)
Text("Joshua Tree National Park")
.font(.subheadline)
}
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
複製程式碼
第五步
修改VStack對齊方式。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
Text("Joshua Tree National Park")
.font(.subheadline)
}
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
複製程式碼
如果不設定對齊方式,VStack預設是內容垂直居中。
第六步
在皮膚中,Command+點按 Joshua Tree National Park 喚起inspector,選擇 Embed in HStack 。
第七步
在location後面新增一個新的文字框,修改文字框文案並設定字型。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Text("California")
.font(.subheadline)
}
}
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
複製程式碼
第八步
可以在兩個水平的文字框之間新增Space來適應寬度。
Space把父檢視在水平或者垂直方向上全部充滿。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
複製程式碼
第九步
最後,利用padding()來設定邊距。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
複製程式碼
建立一個自定義的圖片檢視
我們已經把park名稱和位置的檢視做好了,接下來我們將給park新增個圖片。
你不需要新增很多程式碼,就可以新增一個帶mask、border、shadow的圖片。
第一步
新增一張圖片到asset catalog中。
在Resource資料夾中找到turtlerock.png圖片,然後把它拖拽到asset catalog中。
第二步
選擇 File > New > File 開啟模版選擇皮膚。在 User Interface 區域,選擇 SwiftUI View->Next ,命名為CircleImage.swift。
第三步
把Text構建方法替換成Image。
import SwiftUI
struct CircleImage: View {
var body: some View {
Image("turtlerock")
}
}
struct CircleImage_Preview: PreviewProvider {
static var previews: some View {
CircleImage()
}
}
複製程式碼
第四步
呼叫.clipShape(Circle())方法,建立圓形檢視。
第五步
再建立一個圓圈,用灰色進行填充。並將它作為image的border。
import SwiftUI
struct CircleImage: View {
var body: some View {
Image("turtlerock")
.clipShape(Circle())
.overlay(
Circle().stroke(Color.gray, lineWidth: 4))
}
}
struct CircleImage_Preview: PreviewProvider {
static var previews: some View {
CircleImage()
}
}
複製程式碼
第六步
新增陰影。
第七步
將邊框顏色更改為白色。
import SwiftUI
struct CircleImage: View {
var body: some View {
Image("turtlerock")
.clipShape(Circle())
.overlay(
Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
}
}
struct CircleImage_Preview: PreviewProvider {
static var previews: some View {
CircleImage()
}
}
複製程式碼
UIKit和SwiftUI混合使用
現在我們需要建立一個地圖檢視。你可以MapKit中的MKMapView類來展示渲染地圖介面。
在SwiftUI中要使用UIView或者其子類,你需要讓你的view遵循UIViewRepresentable協議。SwiftUI在WatchKit和AppKit同樣宣告瞭類似的協議。
第一步
建立新的SwiftUI View來展示MKMapView。 File > New > File ,然後建立MapView.swift。
第二步
引入MapKit標頭檔案,並且讓MapView遵循UIViewRepresentable協議。
第三步
UIViewRepresentable協議有兩個協議方法需要實現。第一是UIView(context:)來建立MKMapView。第二個updateUIView(_:context:)來更新view。
把body屬性幹掉,然後UIView(context:)協議方法來建立MKMapView。
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
}
struct MapView_Preview: PreviewProvider {
static var previews: some View {
MapView()
}
}
複製程式碼
第四步
實現updateUIView(_:context:)協議方法,來更新view(設定地圖經緯度等)。
func updateUIView(_ view: MKMapView, context: Context) {
let coordinate = CLLocationCoordinate2D(
latitude: 34.011286, longitude: -116.166868)
let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
let region = MKCoordinateRegion(center: coordinate, span: span)
view.setRegion(region, animated: true)
}
複製程式碼
第五步
當在靜態模式下進行預覽的時候,Xcode只能渲染SwiftUI檢視控制元件。因為MKMapView是UIView子類,所以你需要把模式切換成live模式才能正常預覽。
點選 Live Preview 切換預覽模式。
把上面的子控制元件組合成一個完成的詳情介面
現在我們已經把所有子控制元件定義實現好了。
利用我們現有的工具,我們可以把這些子控制元件組合起來,形成完整的landmarks詳情介面。
第一步
在工程導航區,選擇ContentView.swift檔案。
第二步
在這三個text view控制元件外面,再嵌入一個VStack檢視。
struct ContentView: View {
var body: some View {
VStack {
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack(alignment: .top) {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
}
}
}
複製程式碼
第三步
將你自定義的MapView放在stack的上面。設定MapView的frame。
如果你只設定了Mapview的高度,那麼MapView會自動設定其寬度來適應父檢視。所以MapView會充滿寬度區域。
struct ContentView: View {
var body: some View {
VStack {
MapView()
.frame(height: 300)
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack(alignment: .top) {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
}
}
}
複製程式碼
第四步
點選 Live Preview 來預覽效果。
預覽狀態下,你可以繼續編寫view的程式碼,Live Preview會實時更新檢視。
第五步
將CircleImage新增到stack上面。
struct ContentView: View {
var body: some View {
VStack {
MapView()
.frame(height: 300)
CircleImage()
VStack(alignment: .leading) {
Text("Turtle Rock")
.font(.title)
HStack(alignment: .top) {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
}
}
}
複製程式碼
第六步
調整一下Image的偏移。
第七步
在VStack的底部新增spacer佔位。
第八步
最後設定下 edgesIgnoringSafeArea(.top) 。