簡介
此示例是記錄學習SwiftUI的過程敬拓,原文出自apple.com。
本示例使用SwiftUI完成一個iOS應用程序Landmarks
(地標)棱貌,用于發(fā)現和分享喜歡的地方矮嫉。我們先構建Landmarks
詳情的視圖臊诊。
為了方便布局view坡慌,Landmarks
使用stacks來組合和分層圖像和文本視圖組件。我們需要基于MapKit
構建地圖挚赊,并將其添加到view中诡壁。修改視圖的布局時,Xcode
會提供實時的預覽效果荠割,我們還可以通過Xcode提供的canvas(畫布)輕松的找到對應的代碼妹卿,比如點擊canvas上面的某個view,其對應的代碼就會高亮,請看下圖夺克。
創(chuàng)建項目并預覽畫布
使用xcode創(chuàng)建SwiftUI項目箕宙。瀏覽畫布、預覽和SwiftUI模板代碼铺纽。
要在Xcode中預覽畫布上的視圖并與之交互扒吁,環(huán)境依賴MacOS 10.15和Xcode 11及以上。
創(chuàng)建項目
1.打開Xcode室囊,在Xcode的啟動窗口中單擊
Create a new Xcode projec
,或選擇File > New > Project
魁索。-
2.在模板選擇器中融撞,選擇iOS作為平臺,選擇
Single View App
模板粗蔚,然后單擊Next
尝偎。
-
3.輸入“Landmarks”作為
Product Name
,選擇Use SwiftUI
復選框鹏控,然后單擊Next
致扯。 選擇一個位置以在Mac上保存標記項目。
-
4.在項目導航器中当辐,單擊以選中
ContentView.swift
抖僵。
默認情況下,SwiftUI視圖文件聲明了兩種結構缘揪。 第一個結構符合View
協(xié)議耍群,描述了視圖的內容和布局。 第二個結構聲明該畫布視圖的預覽找筝。
-
5.在畫布中蹈垢,單擊“Resume”以顯示預覽。
如果你的Xcode11中找不到畫布袖裕,請選擇Editor > Editor and Canvas
以顯示它曹抬。
- 6.在
body
屬性中,將“Hello World”更改為自己的問候語急鳄。
當我們更改視圖的body
屬性中的代碼時谤民,右側的預覽畫布會實時顯示我們的改變。
自定義文本視圖
我們可以修改代碼來自定義視圖的顯示攒岛。
在構建Landmarks
應用程序時赖临,可以使用任何編輯器組合: 代碼編輯器(source editor)、 畫布(canvas )或 檢查器(inspectors )灾锯。無論使用哪種工具兢榨,代碼都會保持更新。
- 1.使用檢查器(inspectors)自定義文本視圖。
在預覽畫布中吵聪,長按Command
鍵并單擊Hello World
凌那,此時會彈出結構化編輯窗口,然后選擇Inspect
(檢查器)吟逝。
彈出窗口顯示我們可以根據該控件自定義的不同屬性帽蝶,具體取決于自定義的view類型。
2.使用
Inspect
(檢查器)將文本內容更改為“Turtle Rock”块攒,即您將在應用中顯示的第一個landmark
的名稱励稳。3.修改
Font
為Title
這將系統(tǒng)字體應用于文本,以便它正確響應用戶的首選字體大小和設置囱井。4.手動編輯代碼以添加
.color(.blue)
修飾符; 這會將文本的顏色更改為藍色驹尼。
要自定義SwiftUI視圖,請調用稱為修飾符的方法庞呕。 修改器包裝視圖以更改其顯示或其他屬性新翎。 每個修改器都返回一個新視圖,因此鏈接垂直堆疊的多個修改器是很常見的住练。
我們的代碼始終是視圖的真實來源地啰。 當使用檢查器更改或刪除修改器時,Xcode會立即更新我們的代碼讲逛。
- 5.通過代碼編輯器使用
Inspect
(檢查器)修改控件的樣式亏吝。
這與在預覽畫布上使用Inspect
(檢查器)的操作相同,我們將鼠標放在代碼編輯器中的控件上盏混,然后長按Command
顺呕,并單擊該控件,比如Text("Turtle Rock")
括饶,此時會彈出彈框株茶,我們選擇Inspect
選項后,會彈出像預覽畫布那樣操作后彈出的彈窗图焰,在這個彈窗上面修改控件的樣式即可启盛。
-6.在編輯器中,將彈出窗口中的color
選項設置為Inherited
技羔,就會再次將文本顏色更改為默認的顏色黑色
僵闯。
請注意,此時Xcode會自動更新代碼刪除顏色color(.blue)
修飾符藤滥,以反映在檢查器中的更改鳖粟。
使用Stacks 組合視圖
上面我們這個頁面添加了一個標題視圖,下面我們添加一個詳情描述視圖拙绊,用來顯示位置的向图。
在創(chuàng)建SwiftUI視圖時泳秀,我們可以在視圖的body
屬性中描述其內容、布局和行為; 但是榄攀,body
屬性中只能添加單個視圖嗜傅。 如果要在body中添加多個視圖,可以在Stacks
檩赢,在Stacks
中嵌入多個視圖吕嘀,Stacks
允許三種布局方式:水平HStack
、垂直VStack
贞瞒、從后到前ZStack
組合在一起偶房。
現在我們使用Stacks
的垂直布局方式,將標題和詳情組合在一起军浆。
我們可以使用Xcode的代碼編輯中的Inspect
(檢查器)在body
中添加一個VStack
蝴悉。
-
1.按住
Command
鍵并單擊Text("Turtle Rock")
以顯示結構化編輯彈出窗口,然后選擇Embed in VStack
瘾敢。
2.接下來,通過從庫中拖拽
Text
視圖到VStack
視圖中尿这。
單擊Xcode窗口右上角的加號按鈕(+
)打開庫簇抵,然后在“Turtle Rock”文本視圖后立即將Text
視圖拖到代碼中的位置。
- 3.用
Joshua Tree National Park.
替換文本視圖的占位符文本射众。
根據需求自定義這個文本的字體碟摆。
將剛才添加的
Text
控件的的字體設置為.subheadline
。-
4.
VStack
默認是center
居中對齊叨橱,編輯VStack
的初始化方法典蜕,將其修改為VStack(alignment:.leading)
,按前導對齊視圖罗洗。
接下來愉舔,我們將在該位置Text
的右側添加另一個Text
視圖,用來描述該公園的狀態(tài)伙菜。
- 5.在畫布上轩缤,按住
Command
鍵點擊Joshua Tree National Park
,然后選擇Embed in HStack
贩绕。此時代碼會被自動同步為:
struct ContentView : View {
var body: some View {
VStack(alignment:.leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
}
}
}
}
然后在拖拽一個Text
控件到HStack
中火的,用以顯示狀態(tài)的文本。
- 6.讓布局使用設備的整個寬度淑倾,將
Spacer()
添加到包含兩個文本視圖的水平堆棧來分隔駐留和狀態(tài)馏鹤。
spacer展開以使其包含視圖使用其父視圖的所有空間,而不是僅通過其內容定義其大小娇哆。
- 7.最后湃累,使用
padding()
修飾符方法為地標的名稱和細節(jié)設置間距勃救。
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)
// 讓 HStack 中的子控件寬度充滿整個父視圖
Spacer()
Text(/*@START_MENU_TOKEN@*/"Placeholder"/*@END_MENU_TOKEN@*/)
}
}
// 設置間距
.padding()
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
創(chuàng)建自定義ImageVew
上面我們添加了名稱和詳情文本視圖,接下來要做的是為landmark
添加圖像脱茉。
我們將創(chuàng)建一個自定義視圖剪芥,將遮罩,邊框和陰影應用于圖像琴许,而不是在此文件中添加更多代碼税肪。
首先將圖像添加到項目的Assets.xcassets
中。
- 1.在項目文件的Resources文件夾中找到
turtlerock.png
; 將其拖到Assets.xcassets
中榜田。 Xcode為圖像創(chuàng)建新的圖像集益兄。
接下來,我們將為自定義圖像視圖創(chuàng)建一個新的SwiftUI視圖箭券。
- 2.選擇
File > New > File
以再次打開模板選擇器 在User Interface
部分中净捅,單擊以選中SwiftUI View
,然后單擊Next
辩块。 將文件命名為CircleImage.swift
蛔六,然后單擊Create
。
我們已準備好插入圖像并修改其顯示以匹配所需的設計废亭。
- 3.使用
Image(_:)
初始化方法將默認生成的模板的body
中的Text
視圖替換為Image("turtlerock")
国章。
import SwiftUI
struct CircleImage : View {
var body: some View {
Image("turtlerock")
}
}
#if DEBUG
struct CircleImage_Previews : PreviewProvider {
static var previews: some View {
CircleImage()
}
}
#endif
- 4.調用
.clipShape(Circle())
方法以將ImageView裁切為圓形。
圓形類型是一種可用作蒙版的形狀豆村,或通過為圓形提供筆觸或填充的視圖液兽。
- 5.給圓角添加邊框
- 6.接下來,添加半徑為10點的陰影掌动。
這樣就完成了圖像視圖四啰。
同時使用UIKit
和SwiftUI
的視圖
現在我們已準備好創(chuàng)建地圖視圖。 可以使用MapKit
中的MKMapView
類來渲染地圖粗恢。
要在SwiftUI中
使用UIView
子類柑晒,可以將其他視圖包裝在符合UIViewRepresentable
協(xié)議的SwiftUI
視圖中。 SwiftUI
包含WatchKit
和AppKit
視圖的類似協(xié)議眷射。
首先敦迄,我們將創(chuàng)建一個自定義視圖用于顯示MKMapView
。
1.選擇
File> New> File
凭迹,選擇iOS
作為平臺罚屋,選擇SwiftUI View
模板,然后單擊Next
嗅绸。 將新文件命名為MapView.swift
脾猛,然后單擊Create
。2.使用
import
關鍵字導入MapKit
鱼鸠,并讓MapView
遵守UIViewRepresentable
協(xié)議猛拴。
import SwiftUI
import MapKit
struct MapView : UIViewRepresentable {
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello World!"/*@END_MENU_TOKEN@*/)
}
}
#if DEBUG
struct MapView_Previews : PreviewProvider {
static var previews: some View {
MapView()
}
}
#endif
不要擔心Xcode提示的錯誤; 我們將在接下來的幾個步驟中解決這個問題羹铅。
UIViewRepresentable
協(xié)議有兩個必須要實現的方法:
/// 創(chuàng)建一個要呈現的`UIView`實例。
func makeUIView(context: Self.Context) -> Self.UIViewType
/// 將呈現的`UIView`(和協(xié)調員)更新為最新版本
func updateUIView(_ uiView: Self.UIViewType, context: Self.Context)
- 3.實現
makeUIView(context :)
方法愉昆,用其替換模板中的body
屬性职员,在該方法創(chuàng)建并返回一個空的MKMapView
。
import SwiftUI
import MapKit
struct MapView : UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
MKMapView(frame: .zero)
}
}
#if DEBUG
struct MapView_Previews : PreviewProvider {
static var previews: some View {
MapView()
}
}
#endif
- 4.創(chuàng)建一個
updateUIView(_:context :)
方法跛溉,將地圖視圖的區(qū)域設置為正確的坐標焊切,并讓地圖控件在Turtle Rock上居中。
當預覽處于靜態(tài)模式時芳室,它們僅完全呈現SwiftUI
視圖专肪。 因為MKMapView
是一個UIView
子類,所以需要切換到實時預覽才能看到地圖堪侯。
- 5.單擊
Live Preview
(實時預覽)按鈕可將預覽切換為實時模式嚎尤。 您可能需要單擊預覽上方的Try Again
或Resume
按鈕。
啟動實時預覽后伍宦,我們便能看到地圖上的數據了芽死。
將自定義的MapView
添加到詳情視圖中
我們現在擁有了4個所需的所有組件:1.名稱文本,2.地點文本次洼,3.圓形圖像关贵,4.位置圖。
使用您目前使用的工具滓玖,組合您的自定義視圖以創(chuàng)建標志性詳細視圖的最終設計,下面是效果圖:
1.在項目導航中质蕉,選中
ContentView.swift
文件势篡。2.在另一個
VStack
中嵌入一個包含三個文本視圖的VStack
。
import SwiftUI
struct ContentView : View {
var body: some View {
VStack {
VStack(alignment:.leading) {
Text("Turtle Rock")
.font(.title)
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
// 讓 HStack 中的子控件寬度充滿整個父視圖
Spacer()
Text(/*@START_MENU_TOKEN@*/"Placeholder"/*@END_MENU_TOKEN@*/)
}
}
// 設置間距
.padding()
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
- 3.在根
VStack
中添加剛才自定義的MapView
模暗,設置其frame的高為300禁悠。
當我們僅指定frame
的height
時,視圖會自動調整其內容的寬度兑宇。 在這種情況下碍侦,MapView
會擴展以填充可用空間。
- 4.單擊預覽畫布上的
Live Preview
(實時預覽)按鈕以在組合視圖中查看渲染的地圖隶糕。
您可以在顯示實時預覽時繼續(xù)編輯視圖瓷产。
5.將自定義的
CircleImage
view 添加到根VStack
中,并放在MapView
的下面枚驻。6.要將圖像視圖疊加在地圖視圖的頂部濒旦,請為圖像提供垂直-130個點的偏移量,并從視圖底部填充-130個點再登。
這些調整通過向上移動圖像為文本騰出空間尔邓。
- 7.在根
VStack
外部的底部添加一個spacer
墊片晾剖,將內容與屏幕頂部對齊。
- 8.最后梯嗽,要允許地圖內容擴展到屏幕的上邊緣齿尽,請將
edgesIgnoringSafeArea(.top)
修改器添加到地圖視圖中。