【譯】WWDC2019之SwiftUI

SwiftUI基礎教程

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->Nextide

第三步

輸入項目名稱 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) 。

相關文章
相關標籤/搜索