SwiftUI只支持Xcode 十一、iOS 13版本及以上。git
官方文檔連接:developer.apple.com/tutorials/s…編程
本篇文章將經過一個構建應用(Landmarks,一個能夠發現、分享你喜歡地點的App)示例,來引導你們進行SwiftUI開發。咱們將使用SwiftUI框架來構建Landmark詳情界面。swift
Landmarks利用stacks將圖片和文本組合起來來進行視圖佈局。你須要引用MapKit框架頭文件來建立一個地圖視圖。 你能夠經過Xcode新的實時反饋功能,來優化你的視圖佈局 。bash
1.下載Demo工程。
2.下載Xcode11 Beta。markdown
利用SwiftUI應用模版來建立工程,而後探索瞭解下SwiftUI的畫布。app
爲了可以體驗Xcode 11的view實時預覽和交互功能,必定要確保你的mac系統版本是macOS 10.15 beta。框架
打開 Xcode->Create a new Xcode project,或者經過File > New > Project 來建立工程。編輯器
在模版選擇區域,選擇 iOS->Single View App->Next 。ide
輸入項目名稱 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 )
你有兩種方式來自定義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修改自動更新你的代碼。
咱們建立了一個文本框用來顯示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() } } 複製代碼
如今咱們須要建立一個地圖視圖。你能夠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) 。