🔰Optional Views
此篇討論如何用 SwiftUI 產生 Optional View 的一些方法。
利用 .map()
SwiftUI is perfectly happy working with optional views, such as Image? and Text?. 👉 SwiftUI: Handling optionals - Erica Sadun
let value: Int? = 1
let view = value               // Int?
    .map { Text("\($0)") }     // Text?直接使用 Optional View
上面的 .map() 是間接使用了 Optional View,但這裡的方法是直接使用 Optional View。在下面的範例中,我們必須送兩個 @ViewBuilder closure 給 MyView 使用,讓它可以製造兩個 View,但注意:其實第二個是一個 Optional View (RightContent?),然後 MyView 再拿這兩個 View 到 body 中去製造最後要的結果。
接著,在 MyView 的 extension 中,我們定義了另一個 .init(),只要送進一個 @ViewBuilder closure 給它就可以,第二個 View 會被自動做成 nil (== EmptyView?.none)。
import SwiftUI
// 📦 MyView<LeftContent, RightContent>
struct MyView<LeftContent: View, RightContent: View>: View {
    
    let leftContent : LeftContent
    let rightContent: RightContent?  // ⭐️ Optional<RightContent>
    
    // ⭐️ MyView(makeLeftContent: {}, makeRightContent: {})
    init(
        @ViewBuilder makeLeftContent : () -> LeftContent, 
        @ViewBuilder makeRightContent: () -> RightContent?
    ) {
        self.leftContent  = makeLeftContent()
        self.rightContent = makeRightContent()
    }
    
    var body: some View {     // MyView.Body
        HStack {              // HStack<TupleView<(L, R)>>
            self.leftContent  // L: LeftContent
            self.rightContent // R: Optional<RightContent>
        }
    }
}// 🌀 helper extension
extension MyView where RightContent == EmptyView {
    // ⭐️ MyView(makeLeftContent: {})
    // ⭐️ MyView {}
    init(@ViewBuilder makeLeftContent: () -> LeftContent) {
        self.init(
            makeLeftContent : makeLeftContent, 
            // ⭐️ 這裡的 `nil` 是指 `Optional<EmptyView>.none`
            makeRightContent: { nil }
        )
    }
}// init in extension
let v1 = MyView { Text("Hello") }
// init in definition
let v2 = MyView(makeLeftContent: {
    Text("Hello")
}, makeRightContent: {
    Text("World")
})
// inspect their types
let T1 = type(of: v1)
let T2 = type(of: v2)
print(T1)            // MyView<Text, EmptyView>
print(T2)            // MyView<Text, Text>
print(T1.Body.self)  // HStack<TupleView<(Text, Optional<EmptyView>)>>
print(T2.Body.self)  // HStack<TupleView<(Text, Optional<Text>)>>其他方法
- 📦 Unwrap (只要會使用 .map,Unwrap 是沒有必要的) 
Last updated
Was this helpful?