【譯】WWDC2019之SwiftUI

文章內(nèi)容源處:
https://juejin.im/post/5cf5f4596fb9a07ede0b2fa1#heading-34

SwiftUI基礎(chǔ)教程

SwiftUI只支持Xcode 11、iOS 13版本及以上宫仗。

官方文檔鏈接:developer.apple.com/tutorials/s…

創(chuàng)建組合視圖

本篇文章將通過(guò)一個(gè)構(gòu)建應(yīng)用(Landmarks,一個(gè)可以發(fā)現(xiàn)子巾、分享你喜歡地點(diǎn)的App)示例,來(lái)引導(dǎo)大家進(jìn)行SwiftUI開(kāi)發(fā)小压。我們將使用SwiftUI框架來(lái)構(gòu)建Landmark詳情界面线梗。

Landmarks利用stacks將圖片和文本組合起來(lái)來(lái)進(jìn)行視圖布局。你需要引用MapKit框架頭文件來(lái)創(chuàng)建一個(gè)地圖視圖怠益。 你可以通過(guò)Xcode新的實(shí)時(shí)反饋功能仪搔,來(lái)優(yōu)化你的視圖布局

1.下載Demo工程蜻牢。
2.下載Xcode11 Beta烤咧。

創(chuàng)建工程

利用SwiftUI應(yīng)用模版來(lái)創(chuàng)建工程,然后探索了解下SwiftUI的畫(huà)布抢呆。

為了能夠體驗(yàn)Xcode 11的view實(shí)時(shí)預(yù)覽和交互功能煮嫌,一定要確保你的mac系統(tǒng)版本是macOS 10.15 beta

第一步

打開(kāi) Xcode->Create a new Xcode project抱虐,或者通過(guò)File > New > Project來(lái)創(chuàng)建工程昌阿。

創(chuàng)建工程

第二步

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

Next

第三步

輸入項(xiàng)目名稱 Landmarks->勾選Use SwiftUI->Next保存懦冰。

保存

第四步

在Xcode導(dǎo)航欄,創(chuàng)建ContentView.swift谣沸。通常SwiftUI會(huì)聲明兩個(gè)結(jié)構(gòu)體刷钢。第一個(gè)結(jié)構(gòu)體繼承自View,并且在這兒進(jìn)行View的布局乳附。第二個(gè)結(jié)構(gòu)體聲明了一個(gè)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.

所以這兒聲明的兩個(gè)結(jié)構(gòu)體阱缓,更像是遵循了View和PreviewProvider協(xié)議。


import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello World")
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
復(fù)制代碼
預(yù)覽

第五步

在SwiftUI畫(huà)布中點(diǎn)擊 Resume進(jìn)行視圖預(yù)覽贤重。

預(yù)覽2

Tip:如果畫(huà)布沒(méi)有展示出來(lái)茬祷,可以通過(guò) Editor > Editor and Canvas顯示出來(lái)。

第六步

把Hello World更改為Hello SwiftUI!

當(dāng)你修改文案后并蝗,SwiftUI會(huì)自動(dòng)更新視圖祭犯。(這他么不就是熱重載嘛 Hot-Reload

自定義Text View

你有兩種方式來(lái)自定義TextView。第一種方式是直接修改view代碼滚停,第二種方式是通過(guò)inspector檢查器來(lái)幫助你進(jìn)行代碼編寫(xiě)沃粗。

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

接下來(lái),你將通過(guò)inspector來(lái)自定義Text View

第一步

在preview畫(huà)布上惹想,按住Command鍵+點(diǎn)按Text文本框问词,這時(shí)候inspector就會(huì)被喚起。

inspector彈出框所展示的屬性也會(huì)因?yàn)椴煌腢I控件而有所不同嘀粱。

自定義1

第二步

通過(guò)inspector檢查器修改Text文本框的屬性激挪。

自定義2

第三步

修改文本框字體。

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

自定義3

第四步

手動(dòng)修改代碼垄分,即添加.color(.green) 把文本修改成綠色。
要自定義SwiftUI視圖娃磺,你可以調(diào)用modifiers方法薄湿。Modifiers可以修改視圖的屬性,并且modifier返回一個(gè)新的視圖偷卧,所以通常會(huì)將多個(gè)modifiers像鏈一樣垂直堆疊在一起嘿般。( 說(shuō)白了就是鏈?zhǔn)骄幊蹋空{(diào)用一個(gè)方法就返回自身)涯冠。


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()
    }
}
復(fù)制代碼

你編寫(xiě)的代碼肯定和view是一一對(duì)應(yīng)的炉奴。當(dāng)你通過(guò)inspector修改了view屬性之后,Xcode會(huì)自動(dòng)更新你的代碼蛇更。

第五步

這時(shí)候瞻赶,打開(kāi)inspector,然后把文本Color屬性修改為Inherited派任。

自定義5

第六步

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

利用Stacks組合視圖

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

在這個(gè)篇幅疟丙,我們將使用垂直stack來(lái)顯示park詳情信息嵌巷。

組合視圖

第一步

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

組合視圖1

第二步

接下來(lái),我們將拖拽一個(gè)text view到stack中宋税。

點(diǎn)擊+號(hào)摊崭,打開(kāi)Library面板。拖拽一個(gè)text view到 “Turtle Rock”后面杰赛。

組合視圖2

第三步

修改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()
    }
}
復(fù)制代碼

第五步

修改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()
    }
}
復(fù)制代碼

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

第六步

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

組合視圖6

第七步

在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()
    }
}
復(fù)制代碼

第八步

可以在兩個(gè)水平的文本框之間添加Space來(lái)適應(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()
    }
}
復(fù)制代碼
組合視圖8

第九步

最后扎唾,利用padding()來(lái)設(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()
    }
}
復(fù)制代碼

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

我們已經(jīng)把park名稱和位置的視圖做好了南缓,接下來(lái)我們將給park添加個(gè)圖片胸遇。

你不需要添加很多代碼,就可以添加一個(gè)帶mask汉形、border纸镊、shadow的圖片。

第一步

添加一張圖片到asset catalog中概疆。

在Resource文件夾中找到turtlerock.png圖片逗威,然后把它拖拽到asset catalog中。

圖片視圖

第二步

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

圖片視圖2

第三步

把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()
    }
}
復(fù)制代碼

第四步

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

圖片視圖4

第五步

再創(chuàng)建一個(gè)圓圈弄贿,用灰色進(jìn)行填充春锋。并將它作為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()
    }
}
復(fù)制代碼

第六步

添加陰影差凹。

第七步

將邊框顏色更改為白色。

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()
    }
}
復(fù)制代碼

UIKit和SwiftUI混合使用

現(xiàn)在我們需要?jiǎng)?chuàng)建一個(gè)地圖視圖侧馅。你可以MapKit中的MKMapView類(lèi)來(lái)展示渲染地圖界面危尿。

在SwiftUI中要使用UIView或者其子類(lèi),你需要讓你的view遵循UIViewRepresentable協(xié)議馁痴。SwiftUI在WatchKit和AppKit同樣聲明了類(lèi)似的協(xié)議谊娇。

混用

第一步

創(chuàng)建新的SwiftUI View來(lái)展示MKMapView。 File > New > File罗晕,然后創(chuàng)建MapView.swift济欢。

混用1

第二步

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

第三步

UIViewRepresentable協(xié)議有兩個(gè)協(xié)議方法需要實(shí)現(xiàn)法褥。第一是UIView(context:)來(lái)創(chuàng)建MKMapView。第二個(gè)updateUIView(_:context:)來(lái)更新view酬屉。

把body屬性干掉半等,然后UIView(context:)協(xié)議方法來(lái)創(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()
    }
}
復(fù)制代碼

第四步

實(shí)現(xiàn)updateUIView(_:context:)協(xié)議方法呐萨,來(lái)更新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)
}
復(fù)制代碼

第五步

當(dāng)在靜態(tài)模式下進(jìn)行預(yù)覽的時(shí)候,Xcode只能渲染SwiftUI視圖控件谬擦。因?yàn)镸KMapView是UIView子類(lèi)切距,所以你需要把模式切換成live模式才能正常預(yù)覽。

點(diǎn)擊 Live Preview切換預(yù)覽模式惨远。

混用5

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

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

子控件

第一步

在工程導(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()
        }
    }
}
復(fù)制代碼

第三步

將你自定義的MapView放在stack的上面。設(shè)置MapView的frame缅叠。
如果你只設(shè)置了Mapview的高度悄泥,那么MapView會(huì)自動(dòng)設(shè)置其寬度來(lái)適應(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()
        }
    }
}
復(fù)制代碼
子控件3

第四步

點(diǎn)擊 Live Preview來(lái)預(yù)覽效果弹囚。
預(yù)覽狀態(tài)下,你可以繼續(xù)編寫(xiě)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()
        }
    }
}
復(fù)制代碼

第六步

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

第七步

在VStack的底部添加spacer占位毁渗。

第八步

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

子控件8

作者:一線搬磚工人
鏈接:https://juejin.im/post/5cf5f4596fb9a07ede0b2fa1
來(lái)源:掘金
著作權(quán)歸作者所有单刁。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)灸异,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末羔飞,一起剝皮案震驚了整個(gè)濱河市肺樟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逻淌,老刑警劉巖么伯,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異恍风,居然都是意外死亡蹦狂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)朋贬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凯楔,“玉大人,你說(shuō)我怎么就攤上這事锦募“谕停” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵糠亩,是天一觀的道長(zhǎng)虐骑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赎线,這世上最難降的妖魔是什么廷没? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮垂寥,結(jié)果婚禮上颠黎,老公的妹妹穿的比我還像新娘另锋。我一直安慰自己,他們只是感情好狭归,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布夭坪。 她就那樣靜靜地躺著,像睡著了一般过椎。 火紅的嫁衣襯著肌膚如雪室梅。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天疚宇,我揣著相機(jī)與錄音亡鼠,去河邊找鬼。 笑死灰嫉,一個(gè)胖子當(dāng)著我的面吹牛拆宛,可吹牛的內(nèi)容都是我干的嗓奢。 我是一名探鬼主播讼撒,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼股耽!你這毒婦竟也來(lái)了根盒?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤物蝙,失蹤者是張志新(化名)和其女友劉穎炎滞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體诬乞,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡册赛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了震嫉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片森瘪。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖票堵,靈堂內(nèi)的尸體忽然破棺而出扼睬,到底是詐尸還是另有隱情,我是刑警寧澤悴势,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布窗宇,位于F島的核電站,受9級(jí)特大地震影響特纤,放射性物質(zhì)發(fā)生泄漏军俊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一捧存、第九天 我趴在偏房一處隱蔽的房頂上張望粪躬。 院中可真熱鬧官硝,春花似錦、人聲如沸短蜕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)朋魔。三九已至岖研,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間警检,已是汗流浹背孙援。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扇雕,地道東北人拓售。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像镶奉,于是被迫代替她去往敵國(guó)和親础淤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,097評(píng)論 1 32
  • 由于 API 變動(dòng)哨苛,此文章部分內(nèi)容已失效鸽凶,最新完整中文教程及代碼請(qǐng)查看 https://github.com/Wi...
    Willie_閱讀 7,870評(píng)論 29 23
  • 翻譯自“Auto Layout Guide”。 2 自動(dòng)布局細(xì)則手冊(cè) 2.1 堆棧視圖 接下來(lái)的章節(jié)展示了如何使用...
    lakerszhy閱讀 1,864評(píng)論 3 9
  • 01 今天是6月7號(hào)建峭,高考第一天玻侥,看著那時(shí)間的跳動(dòng),我的思緒也回到了21年前亿蒸。 那時(shí)候...
    清揚(yáng)在諾閱讀 320評(píng)論 0 3
  • 昨日在1班進(jìn)行復(fù)習(xí)單元的講解凑兰,但是在6班仍舊是15個(gè)詞匯的講解和熟記,我在思考對(duì)于該班的學(xué)生該如何進(jìn)行學(xué)習(xí)边锁。 他們...
    思彤lu閱讀 158評(píng)論 0 0