WWDC - SwiftUI - 初戀般的感覺

*SwiftUI is a modern way to declare user interfaces for any Apple platform. Create beautiful, dynamic apps faster than ever before.

一種牛逼的更加快速,更加漂亮的用戶界面的方法

創(chuàng)建和組合視圖

  • 本篇文章將通過一個(gè)構(gòu)建應(yīng)用(Landmarks,一個(gè)可以發(fā)現(xiàn)、分享你喜歡地點(diǎn)的App)示例,來引導(dǎo)大家進(jìn)行SwiftUI開發(fā)。我們將使用SwiftUI框架來構(gòu)建Landmark詳情界面。
  • Landmarks利用stacks將圖片和文本組合起來來進(jìn)行視圖布局。你需要引用MapKit框架頭文件來創(chuàng)建一個(gè)地圖視圖。 你可以通過Xcode新的實(shí)時(shí)反饋功能,來優(yōu)化你的視圖布局 。

創(chuàng)建一個(gè)使用SwiftUI的新Xcode項(xiàng)目。瀏覽畫布、預(yù)覽和SwiftUI模板代碼。

要在Xcode中預(yù)覽畫布上的視圖并與之交互,請(qǐng)確保您的Mac運(yùn)行的是macOS 10.15 beta版

macOS 10.15 beta版下載地址
Xcode 11下載地址

第一步

  • 打開 Xcode->Create a new Xcode project,或者通過File > New > Project 來創(chuàng)建工程。

第二步

  • 在模版選擇區(qū)域,選擇 iOS->Single View App->Next 。

第三步

  • 輸入項(xiàng)目名稱 LGSwiftUIDemo->勾選Use SwiftUI->Next 保存。
    記得一定要選擇語言:Swift 然后勾選 Use SwiftUI

點(diǎn)擊之后你就會(huì)感覺發(fā)現(xiàn)了新東西咯:

  • 左邊沒有了ViewController 多了sceneDelegate和ContentView
  • 中間代碼樣式不一樣了
  • 右邊多出一塊預(yù)顯示欄,很牛逼

默認(rèn)情況下,SwiftUI視圖文件聲明兩個(gè)結(jié)構(gòu)。

  • 第一個(gè)結(jié)構(gòu)符合視圖協(xié)議,描述了視圖的內(nèi)容和布局。
  • 第二個(gè)結(jié)構(gòu)聲明了該視圖的預(yù)覽。

現(xiàn)在我們來玩玩預(yù)覽:

如果畫布沒有展示出來,可以通過 Editor > Editor and Canvas 顯示出來。

第四步

把Hello World更改為Hello SwiftUI!
當(dāng)你修改文案后,SwiftUI會(huì)自動(dòng)更新視圖。


自定義Text View

你有兩種方式來自定義TextView。

  • 第一種方式是直接修改view代碼
  • 第二種方式是通過inspector檢查器來幫助你進(jìn)行代碼編寫。

當(dāng)你構(gòu)建Landmarks的時(shí)候,你可以運(yùn)用任何一個(gè)編輯器來進(jìn)行編碼工作:直接修改源代碼、通過畫布、通過inspector view檢查器。代碼并不會(huì)關(guān)心你用什么工具,它始終能夠保持最新狀態(tài)

接下來,你將通過inspector來自定義Text View

第一步

  • preview畫布上,按住Command鍵+點(diǎn)按Text文本框,這時(shí)候inspector就會(huì)被喚起。
    inspector彈出框所展示的屬性也會(huì)因?yàn)椴煌腢I控件而有所不同。

第二步

通過inspector檢查器修改Text文本框的屬性。

第三步

  • 修改文本框字體。
  • 修改文本框字體是利用的系統(tǒng)的字體。

第四步

  • 手動(dòng)修改代碼,即添加.color(.green)把文本修改成綠色。
  • 要自定義SwiftUI視圖,你可以調(diào)用modifiers方法。Modifiers可以修改視圖的屬性,并且modifier返回一個(gè)新的視圖,所以通常會(huì)將多個(gè)modifiers像鏈一樣垂直堆疊在一起。( 鏈?zhǔn)骄幊?/strong>)。
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是一一對(duì)應(yīng)的。當(dāng)你通過inspector修改了view屬性之后,Xcode會(huì)自動(dòng)更新你的代碼。

第五步

這時(shí)候,打開inspector,然后把文本Color屬性修改為Inherited。

第六步

注意一點(diǎn)的就是,Xcode會(huì)根據(jù)inspector修改自動(dòng)更新你的代碼。

利用Stacks組合視圖

我們創(chuàng)建了一個(gè)文本框用來顯示landmark的詳情信息,并且把這個(gè)文本控件放到頭部。
當(dāng)我們創(chuàng)建SwiftUI視圖控件的時(shí)候,我們會(huì)把控件的內(nèi)容、布局還有一些行為放在body屬性中;然而body屬性只返回了一個(gè)view。你可以利用stacks嵌入多個(gè)view,它可以垂直嵌入、水平嵌入等。
在這里,我們將使用垂直stack來顯示park詳情信息。

第一步

Command+點(diǎn)按text初始化方法區(qū)域。選擇Embed in VStack

第二步

  • 接下來,我們將拖拽一個(gè)text viewstack中。
  • 點(diǎn)擊+號(hào),打開Library面板。拖拽一個(gè)text view到 “Turtle Rock”后面 。

第三步

修改text view文案為Joshua Tree National Park

第四步

設(shè)置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對(duì)齊方式。


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()
    }
}

如果不設(shè)置對(duì)齊方式,VStack默認(rèn)是內(nèi)容垂直居中。

第六步

在面板中,Command+點(diǎn)按 Joshua Tree National Park喚起inspector,選擇Embed in HStack。

第七步

location后面添加一個(gè)新的文本框,修改文本框文案并設(shè)置字體


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()
    }
}

第八步

  • 可以在兩個(gè)水平的文本框之間添加Space來適應(yīng)寬度。
  • 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()來設(shè)置邊距。


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()
    }
}

創(chuàng)建一個(gè)自定義的圖片視圖

我們已經(jīng)把park名稱和位置的視圖做好了,接下來我們將給park添加個(gè)圖片。
你不需要添加很多代碼,就可以添加一個(gè)帶mask、border、shadow的圖片。

第一步

添加一張圖片到asset catalog中。
Resource文件夾中找到turtlerock.png圖片,然后把它拖拽到asset catalog中。

第二步

選擇File > New > File打開模版選擇面板。在 User Interface區(qū)域,選擇 SwiftUI View->Next ,命名為CircleImage.swift。

第三步

Text構(gòu)建方法替換成Image。

import SwiftUI

struct CircleImage: View {
    var body: some View {
        Image("turtlerock")
    }
}

struct CircleImage_Preview: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}

第四步

調(diào)用.clipShape(Circle())方法,創(chuàng)建圓形視圖。

第五步

再創(chuàng)建一個(gè)圓圈,用灰色進(jìn)行填充。并將它作為imageborder

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混合使用

現(xiàn)在我們需要?jiǎng)?chuàng)建一個(gè)地圖視圖。你可以MapKit中的MKMapView類來展示渲染地圖界面。
SwiftUI中要使用UIView或者其子類,你需要讓你的view遵循UIViewRepresentable協(xié)議SwiftUIWatchKitAppKit同樣聲明了類似的協(xié)議

第一步

創(chuàng)建新的SwiftUI View來展示MKMapView。 File > New > File,然后創(chuàng)建MapView.swift

第二步

引入MapKit頭文件,并且讓MapView遵循UIViewRepresentable協(xié)議。

第三步

UIViewRepresentable協(xié)議有兩個(gè)協(xié)議方法需要實(shí)現(xiàn)。第一是UIView(context:)來創(chuàng)建MKMapView。第二個(gè)updateUIView(_:context:)來更新view
body屬性干掉,然后UIView(context:)協(xié)議方法來創(chuàng)建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()
    }
}

第四步

實(shí)現(xiàn)updateUIView(_:context:)協(xié)議方法,來更新view(設(shè)置地圖經(jīng)緯度等)。

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)
}

第五步

當(dāng)在靜態(tài)模式下進(jìn)行預(yù)覽的時(shí)候,Xcode只能渲染SwiftUI視圖控件。因?yàn)?code>MKMapView是UIView子類,所以你需要把模式切換成live模式才能正常預(yù)覽。
點(diǎn)擊Live Preview切換預(yù)覽模式。

把上面的子控件組合成一個(gè)完成的詳情界面

現(xiàn)在我們已經(jīng)把所有子控件定義實(shí)現(xiàn)好了。
利用我們現(xiàn)有的工具,我們可以把這些子控件組合起來,形成完整的landmarks詳情界面。

image.png

第一步

在工程導(dǎo)航區(qū),選擇ContentView.swift文件。

第二步

在這三個(gè)text view控件外面,再嵌入一個(gè)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的上面。設(shè)置MapViewframe
如果你只設(shè)置了Mapview的高度,那么MapView會(huì)自動(dòng)設(shè)置其寬度來適應(yīng)父視圖。所以MapView會(huì)充滿寬度區(qū)域。

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()
        }
    }
}

第四步

點(diǎn)擊Live Preview來預(yù)覽效果。
預(yù)覽狀態(tài)下,你可以繼續(xù)編寫view的代碼,Live Preview會(huì)實(shí)時(shí)更新視圖。

第五步

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()
        }
    }
}

第六步

調(diào)整一下Image的偏移。

第七步

VStack的底部添加spacer占位。

第八步

最后設(shè)置下 edgesIgnoringSafeArea(.top) 。

整體寫下來,就是感覺很簡(jiǎn)單,很舒服.更加快速的面向開發(fā),此時(shí)此刻還有誰!
Swift 寫天寫地寫世界,千秋萬載,一統(tǒng)江湖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容