筆記
本篇文章記錄一下100 Days of SwiftUI
第23-25天的筆記內(nèi)容
為什么 SwiftUI 使用結(jié)構(gòu)體作為視圖伴箩?
// 性能因素:結(jié)構(gòu)比類更簡單、更快
// 迫使我們考慮以一種干凈的方式隔離狀態(tài)贬堵,因為類可以自由更改其值带族,這可能會導(dǎo)致代碼更加混亂
// 如果在視圖中使用類锁荔,可能會發(fā)現(xiàn)的代碼無法編譯或在運行時崩潰,所以使用結(jié)構(gòu)
SwiftUI 主視圖背后是什么炉菲?
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
.background(.red)
}
}
// 這樣并不能實現(xiàn)整個屏幕為紅色堕战,因為Text背后沒有任何東西坤溃,想要整個屏幕為紅色應(yīng)該讓Text占據(jù)整個屏幕的空間
Text("Hello, world!")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.red)
為什么修飾符順序很重要拍霜?
Button("Hello, world!") {
// do nothing
}
.background(.red)
.frame(width: 200, height: 200)
// 以上的代碼顯示效果并不會看到帶有“Hello, world!”的200x200紅色按鈕嘱丢,而是看到一個200x200的空方塊,上面寫著“Hello, world!” 位于中間祠饺,并在“Hello, world!”周圍有一個紅色矩形
// 這是因為:每個修飾符都會應(yīng)用該修飾符創(chuàng)建一個新結(jié)構(gòu)越驻,而不是僅僅在視圖上設(shè)置屬性
print(type(of: self.body))
// 打印ModifiedContent<ModifiedContent<Button<Text>, _BackgroundStyleModifier<Color>>, _FrameLayout>
// 1.每次我們修改視圖時,SwiftUI 都會通過使用泛型來應(yīng)用該修飾符:ModifiedContent<OurThing, OurModifier>道偷。
// 2.當(dāng)我們應(yīng)用多個修飾符時缀旁,它們只會疊加:ModifiedContent<ModifiedContent<…
// 3.要讀取類型是什么,請從最里面的類型開始并逐步解決勺鸦,每個類型都需要一個要轉(zhuǎn)換的視圖以及要進行的實際更改并巍,而不是直接修改視圖,所以首先按鈕有一些應(yīng)用了背景顏色的文本换途,然后給它一個更大的框架
為什么 SwiftUI 使用“some View”作為其視圖類型懊渡?
// 1.對性能很重要,SwiftUI 需要能夠查看我們顯示的視圖并了解它們?nèi)绾巫兓猓员闼梢哉_更新用戶界面
// 2.因為 SwiftUI 使用ModifiedContent剃执,該View協(xié)議有一個關(guān)聯(lián)的類型,所以View它本身沒有任何意義懈息,我們需要確切地說出它是什么類型的視圖
// VStack是如何工作的肾档?
// 使用VStack時SwiftUI會創(chuàng)建一個TupleView,包含VStack中的視圖辫继,TupleView只能處理10個視圖怒见,也就是為什么SwiftUI 不允許父級內(nèi)部有超過 10 個視圖的原因
// body中創(chuàng)建視圖會做什么處理?
// 與VStack原理相同也是創(chuàng)建一個TupleView包含這些視圖姑宽,并設(shè)置給body的@ViewBuilder這個特殊屬性
條件修飾符
// 通常希望修飾符僅在滿足特定條件時應(yīng)用遣耍,而在 SwiftUI 中,最簡單的方法是使用三元條件運算符
struct ContentView: View {
@State private var useRedText = false
var body: some View {
Button("Hello World") {
// flip the Boolean between true and false
useRedText.toggle()
}
.foregroundColor(useRedText ? .red : .blue)
}
}
環(huán)境修飾符
// 許多修飾符可以應(yīng)用于容器低千,這允許我們同時將相同的修飾符應(yīng)用于多個視圖
VStack {
Text("Gryffindor")
.font(.largeTitle) // 子視圖中的修飾符任會替換相同的環(huán)境修飾符配阵,Gryffindor會具有大標(biāo)題
Text("Hufflepuff")
Text("Ravenclaw")
Text("Slytherin")
}
.font(.title)
// 由上述特性可以知道font()是一個環(huán)境修飾符
VStack {
Text("Gryffindor")
.blur(radius: 0)
Text("Hufflepuff")
Text("Ravenclaw")
Text("Slytherin")
}
.blur(radius: 5)
// 而blur()是一個常規(guī)修改器,因此應(yīng)用于子視圖的任何模糊都會添加到VStack模糊中示血,而不是替換它
視圖作為屬性
// 有很多方法可以讓您更輕松地在 SwiftUI 中使用復(fù)雜的視圖層次結(jié)構(gòu)棋傍,其中一種選擇是使用屬性
// 創(chuàng)建一個視圖作為您自己視圖的屬性,然后在布局中使用該屬性
struct ContentView: View {
let motto1 = Text("Draco dormiens")
let motto2 = Text("nunquam titillandus")
var body: some View {
VStack {
motto1
.foregroundColor(.red)
motto2
.foregroundColor(.blue)
}
}
}
// Swift 不允許我們創(chuàng)建一個引用其他存儲屬性的存儲屬性难审,因為這會在創(chuàng)建對象時引起問題
// 這意味著嘗試創(chuàng)建TextField與本地屬性的綁定將會導(dǎo)致問題
// 但是可以創(chuàng)建計算屬性
var motto1: some View {
Text("Draco dormiens")
}
// 但是與body不用瘫拣,Swift 不會自動@ViewBuilder在此處應(yīng)用該屬性,因此如果想返回多個視圖還需要調(diào)整告喊,提供一下3種方式
// 1.將視圖放在堆棧中
var spells: some View {
VStack {
Text("Lumos")
Text("Obliviate")
}
}
// 2.返回一個Group
var spells: some View {
Group {
Text("Lumos")
Text("Obliviate")
}
}
// 3.自己添加@ViewBuilder屬性
@ViewBuilder var spells: some View {
Text("Lumos")
Text("Obliviate")
}
視圖組成
// SwiftUI 允許我們將復(fù)雜的視圖分解為更小的視圖麸拄,而不會產(chǎn)生太大的性能影響
struct ContentView: View {
var body: some View {
VStack(spacing: 10) {
Text("First")
.font(.largeTitle)
.padding()
.foregroundColor(.white)
.background(.blue)
.clipShape(Capsule())
Text("Second")
.font(.largeTitle)
.padding()
.foregroundColor(.white)
.background(.blue)
.clipShape(Capsule())
}
}
}
// 可以修改為:
struct CapsuleText: View {
var text: String
var body: some View {
Text(text)
.font(.largeTitle)
.padding()
.foregroundColor(.white)
.background(.blue)
.clipShape(Capsule())
}
}
struct ContentView: View {
var body: some View {
VStack(spacing: 10) {
CapsuleText(text: "First")
CapsuleText(text: "Second")
}
}
}
自定義修飾符
// SwiftUI允許創(chuàng)建執(zhí)行特定操作的自定義修飾符
// 創(chuàng)建一個符合ViewModifier協(xié)議的新結(jié)構(gòu)派昧,且必須調(diào)用body方法接受要使用的內(nèi)容,并且必須返回some View
struct Title: ViewModifier {
func body(content: Content) -> some View {
content
.font(.largeTitle)
.foregroundColor(.white)
.padding()
.background(.blue)
.clipShape(RoundedRectangle(cornerRadius: 10))
}
}
Text("Hello World")
.modifier(Title())
// 使用自定義修飾符時拢切,j建議創(chuàng)建View擴展使用
extension View {
func titleStyle() -> some View {
modifier(Title())
}
}
Text("Hello World")
.titleStyle()
// 自定義修飾符還可以根據(jù)需要創(chuàng)建新的視圖結(jié)構(gòu)
struct Watermark: ViewModifier {
var text: String
func body(content: Content) -> some View {
ZStack(alignment: .bottomTrailing) {
content
Text(text)
.font(.caption)
.foregroundColor(.white)
.padding(5)
.background(.black)
}
}
}
extension View {
func watermarked(with text: String) -> some View {
modifier(Watermark(text: text))
}
}
Color.blue
.frame(width: 300, height: 200)
.watermarked(with: "Hacking with Swift")