SwiftUI 01-創(chuàng)建和組合視圖 (Creating and Combining Views)

本章Demo 鏈接
Blog 鏈接

簡介

此示例是記錄學習SwiftUI的過程敬拓,原文出自apple.com

本示例使用SwiftUI完成一個iOS應用程序Landmarks(地標)棱貌,用于發(fā)現和分享喜歡的地方矮嫉。我們先構建Landmarks詳情的視圖臊诊。
為了方便布局view坡慌,Landmarks使用stacks來組合和分層圖像和文本視圖組件。我們需要基于MapKit構建地圖挚赊,并將其添加到view中诡壁。修改視圖的布局時,Xcode會提供實時的預覽效果荠割,我們還可以通過Xcode提供的canvas(畫布)輕松的找到對應的代碼妹卿,比如點擊canvas上面的某個view,其對應的代碼就會高亮,請看下圖夺克。

Snip20190608_5.png

創(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尝偎。

    Snip20190608_1.png

  • 3.輸入“Landmarks”作為Product Name,選擇Use SwiftUI復選框鹏控,然后單擊Next致扯。 選擇一個位置以在Mac上保存標記項目。

    Snip20190608_6.png

  • 4.在項目導航器中当辐,單擊以選中ContentView.swift抖僵。
    默認情況下,SwiftUI視圖文件聲明了兩種結構缘揪。 第一個結構符合View協(xié)議耍群,描述了視圖的內容和布局。 第二個結構聲明該畫布視圖的預覽找筝。

    Snip20190608_8.png

  • 5.在畫布中蹈垢,單擊“Resume”以顯示預覽。


    Snip20190608_9.png

如果你的Xcode11中找不到畫布袖裕,請選擇Editor > Editor and Canvas以顯示它曹抬。

Snip20190608_10.png

  • 6.在body屬性中,將“Hello World”更改為自己的問候語急鳄。
    Snip20190608_13.png

當我們更改視圖的body屬性中的代碼時谤民,右側的預覽畫布會實時顯示我們的改變。

自定義文本視圖

我們可以修改代碼來自定義視圖的顯示攒岛。
在構建Landmarks應用程序時赖临,可以使用任何編輯器組合: 代碼編輯器(source editor)、 畫布(canvas )或 檢查器(inspectors )灾锯。無論使用哪種工具兢榨,代碼都會保持更新。

Snip20190608_14.png
  • 1.使用檢查器(inspectors)自定義文本視圖。
    在預覽畫布中吵聪,長按Command鍵并單擊Hello World凌那,此時會彈出結構化編輯窗口,然后選擇Inspect(檢查器)吟逝。
    Snip20190608_15.png

彈出窗口顯示我們可以根據該控件自定義的不同屬性帽蝶,具體取決于自定義的view類型。

  • 2.使用Inspect(檢查器)將文本內容更改為“Turtle Rock”块攒,即您將在應用中顯示的第一個landmark的名稱励稳。

  • 3.修改FontTitle
    這將系統(tǒng)字體應用于文本,以便它正確響應用戶的首選字體大小和設置囱井。

  • 4.手動編輯代碼以添加.color(.blue)修飾符; 這會將文本的顏色更改為藍色驹尼。
    要自定義SwiftUI視圖,請調用稱為修飾符的方法庞呕。 修改器包裝視圖以更改其顯示或其他屬性新翎。 每個修改器都返回一個新視圖,因此鏈接垂直堆疊的多個修改器是很常見的住练。

Snip20190608_17.png

我們的代碼始終是視圖的真實來源地啰。 當使用檢查器更改或刪除修改器時,Xcode會立即更新我們的代碼讲逛。

  • 5.通過代碼編輯器使用Inspect(檢查器)修改控件的樣式亏吝。
    這與在預覽畫布上使用Inspect(檢查器)的操作相同,我們將鼠標放在代碼編輯器中的控件上盏混,然后長按Command顺呕,并單擊該控件,比如Text("Turtle Rock")括饶,此時會彈出彈框株茶,我們選擇Inspect選項后,會彈出像預覽畫布那樣操作后彈出的彈窗图焰,在這個彈窗上面修改控件的樣式即可启盛。
    Snip20190608_22.png

-6.在編輯器中,將彈出窗口中的color選項設置為Inherited技羔,就會再次將文本顏色更改為默認的顏色黑色僵闯。
請注意,此時Xcode會自動更新代碼刪除顏色color(.blue)修飾符藤滥,以反映在檢查器中的更改鳖粟。

Snip20190608_23.png

使用Stacks 組合視圖

上面我們這個頁面添加了一個標題視圖,下面我們添加一個詳情描述視圖拙绊,用來顯示位置的向图。
在創(chuàng)建SwiftUI視圖時泳秀,我們可以在視圖的body屬性中描述其內容、布局和行為; 但是榄攀,body屬性中只能添加單個視圖嗜傅。 如果要在body中添加多個視圖,可以在Stacks檩赢,在Stacks中嵌入多個視圖吕嘀,Stacks允許三種布局方式:水平HStack、垂直VStack贞瞒、從后到前ZStack 組合在一起偶房。

546a4d34-fef9-4574-a405-d16ec83ca7fe.png

現在我們使用Stacks的垂直布局方式,將標題和詳情組合在一起军浆。

我們可以使用Xcode的代碼編輯中的Inspect(檢查器)在body中添加一個VStack蝴悉。

  • 1.按住Command鍵并單擊Text("Turtle Rock")以顯示結構化編輯彈出窗口,然后選擇Embed in VStack瘾敢。

    Snip20190608_26.png

  • 2.接下來,通過從庫中拖拽Text視圖到VStack視圖中尿这。
    單擊Xcode窗口右上角的加號按鈕(+)打開庫簇抵,然后在“Turtle Rock”文本視圖后立即將Text視圖拖到代碼中的位置。

Snip20190608_29.png
  • 3.用Joshua Tree National Park.替換文本視圖的占位符文本射众。

根據需求自定義這個文本的字體碟摆。

  • 將剛才添加的Text控件的的字體設置為.subheadline

  • 4.VStack默認是center居中對齊叨橱,編輯VStack的初始化方法典蜕,將其修改為VStack(alignment:.leading),按前導對齊視圖罗洗。

    Snip20190608_30.png

接下來愉舔,我們將在該位置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)馏鹤。
    Snip20190608_32.png

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
Snip20190608_33.png

我們已準備好插入圖像并修改其顯示以匹配所需的設計废亭。

  • 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裁切為圓形。
    圓形類型是一種可用作蒙版的形狀豆村,或通過為圓形提供筆觸或填充的視圖液兽。
Snip20190608_34.png
  • 5.給圓角添加邊框
Snip20190608_35.png
  • 6.接下來,添加半徑為10點的陰影掌动。
Snip20190608_37.png

這樣就完成了圖像視圖四啰。

同時使用UIKitSwiftUI的視圖

現在我們已準備好創(chuàng)建地圖視圖。 可以使用MapKit中的MKMapView類來渲染地圖粗恢。
要在SwiftUI中使用UIView子類柑晒,可以將其他視圖包裝在符合UIViewRepresentable協(xié)議的SwiftUI視圖中。 SwiftUI包含WatchKitAppKit視圖的類似協(xié)議眷射。

b9753927-fb44-4f74-876f-31d9126cbb16.png

首先敦迄,我們將創(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 AgainResume按鈕。
Snip20190608_38.png

啟動實時預覽后伍宦,我們便能看到地圖上的數據了芽死。

將自定義的MapView添加到詳情視圖中

我們現在擁有了4個所需的所有組件:1.名稱文本,2.地點文本次洼,3.圓形圖像关贵,4.位置圖。
使用您目前使用的工具滓玖,組合您的自定義視圖以創(chuàng)建標志性詳細視圖的最終設計,下面是效果圖:


973ba702-85db-4852-851f-86a94cfca002.png
  • 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禁悠。
Snip20190608_39.png

當我們僅指定frameheight時,視圖會自動調整其內容的寬度兑宇。 在這種情況下碍侦,MapView會擴展以填充可用空間。

  • 4.單擊預覽畫布上的Live Preview(實時預覽)按鈕以在組合視圖中查看渲染的地圖隶糕。

您可以在顯示實時預覽時繼續(xù)編輯視圖瓷产。

  • 5.將自定義的CircleImage view 添加到根VStack中,并放在MapView的下面枚驻。

  • 6.要將圖像視圖疊加在地圖視圖的頂部濒旦,請為圖像提供垂直-130個點的偏移量,并從視圖底部填充-130個點再登。

這些調整通過向上移動圖像為文本騰出空間尔邓。

  • 7.在根VStack外部的底部添加一個spacer墊片晾剖,將內容與屏幕頂部對齊。
Snip20190608_40.png
  • 8.最后梯嗽,要允許地圖內容擴展到屏幕的上邊緣齿尽,請將edgesIgnoringSafeArea(.top)修改器添加到地圖視圖中。
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末灯节,一起剝皮案震驚了整個濱河市循头,隨后出現的幾起案子,更是在濱河造成了極大的恐慌显晶,老刑警劉巖贷岸,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異磷雇,居然都是意外死亡偿警,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門唯笙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來螟蒸,“玉大人,你說我怎么就攤上這事崩掘∑呦樱” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵苞慢,是天一觀的道長诵原。 經常有香客問我,道長挽放,這世上最難降的妖魔是什么绍赛? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮辑畦,結果婚禮上吗蚌,老公的妹妹穿的比我還像新娘。我一直安慰自己纯出,他們只是感情好蚯妇,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著暂筝,像睡著了一般箩言。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上焕襟,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天分扎,我揣著相機與錄音,去河邊找鬼胧洒。 笑死畏吓,一個胖子當著我的面吹牛墨状,可吹牛的內容都是我干的。 我是一名探鬼主播菲饼,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼肾砂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宏悦?” 一聲冷哼從身側響起镐确,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饼煞,沒想到半個月后源葫,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡砖瞧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年息堂,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片块促。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡荣堰,死狀恐怖,靈堂內的尸體忽然破棺而出竭翠,到底是詐尸還是另有隱情振坚,我是刑警寧澤傀蓉,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布乘盼,位于F島的核電站槽地,受9級特大地震影響鞭执,放射性物質發(fā)生泄漏。R本人自食惡果不足惜密似,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一锁摔、第九天 我趴在偏房一處隱蔽的房頂上張望里烦。 院中可真熱鬧损离,春花似錦哥艇、人聲如沸绝编。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽十饥。三九已至窟勃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逗堵,已是汗流浹背秉氧。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蜒秤,地道東北人汁咏。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓亚斋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親攘滩。 傳聞我的和親對象是個殘疾皇子帅刊,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容