iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0

https://ithelp.ithome.com.tw/upload/images/20231009/20130138XZUrFSgNhP.jpg
Photo by Sébastien Goldberg on Unsplash
Lake Tekapo, Nouvelle-Zélande

Create Child Views with ViewBuilder
https://ithelp.ithome.com.tw/upload/images/20231009/20130138rO0QeIUrEi.png
歡迎來到 ViewBuilder [坐殺博徒].🎲

在 Swift 的 SwiftUI 中,@ViewBuilder 是一個特殊的屬性修飾符,用於建立和返回一組可視視圖。它允許我們使用像 if-else 和 for-in 這樣的控制結構來創建複雜的視圖層次結構。你可以把它想像成一個專為視圖設計的閉包。

@ViewBuilder 作用在於它能夠把多個視圖組合成一個視圖。例如,你可能有這樣的需求:根據某些條件顯示或隱藏某個視圖。傳統的做法是使用多個 if 判斷,但這會導致代碼變得繁瑣。有了 @ViewBuilder,你可以簡單地在一個閉包中描述視圖的組成,而不需要擔心如何組合它們。

舉個例子:

struct MyView: View {
    var showText: Bool

    var body: some View {
        content
    }

    @ViewBuilder
    var content: some View {
        if showText {
            Text("Hello, World!")
        }
        Text("Always visible.")
    }
}

一句話解釋:「@ViewBuilder View 版 closure」

什麼!叫我用 ViewBuilder 刻這UI?!
https://ithelp.ithome.com.tw/upload/images/20231009/20130138q5N8fv8ry7.png
Figma 先有設計稿在說 ( 逃


https://ithelp.ithome.com.tw/upload/images/20231009/201301385BiVVxWW4F.png

struct FeedbackRatingView<Content: View>: View {
    let content: () -> Content
    
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }
    
    var body: some View {
        content()
            .padding(.horizontal, 12)
            .padding(16)
    }
}
extension View {
    func feedbackRatingAlert<Content: View>(
        isPresented: Binding<Bool>,
        message: Binding<String>,
        textStyle: Binding<UIFont.TextStyle>,
        placeholderText: Binding<String>,
        rating: Binding<Int>,
        isLoading: Binding<Bool>,
        @ViewBuilder content: () -> Content
    ) -> some View {
        self.overlay(
            ZStack(alignment: .center) {
                
                if isPresented.wrappedValue {
                    FeedbackRatingView {
										/.../
                    }
                }
            }
        )
    }
}
.feedbackRatingAlert(isPresented: $showingFeedback,
                             message: $message,
                             textStyle: $textStyle,
                             placeholderText: $placeholderText,
                             rating: $rating,
                             isLoading: $isLoading) {
            
        }

這一段 Swift 代碼主要定義了一個 SwiftUI 的自定義組件和一個擴展(extension)。我會逐一地解釋這些部分和它們之間的關係:

  1. FeedbackRatingView:

    這是一個通用組件,它接受一個返回 Content 類型的 closure。這意味著你可以將任何 View 作為其內容插入。

    • let content: () -> Content: 這是存儲你提供的 closure 的屬性。
    • init(@ViewBuilder content: @escaping () -> Content): 這是一個特殊的初始化函數,利用 @ViewBuilder 屬性包裝器來接受一個或多個 view 並將其包裝成一個單一的 view。
    • body: 定義了組件的主體。它將你提供的內容加上了一些內外間距。
  2. View 的擴展(extension):

    這個擴展為任何 SwiftUI 的 View 添加了一個名為 feedbackRatingAlert 的方法。該方法允許你在主 view 上方顯示一個自定義的叠加層,當某個條件(isPresented)為 true 時。

    • 該方法接受了多個綁定(Binding),這允許父 view 和叠加層共享和互動這些變數。
    • 這個方法也接受一個 @ViewBuilder closure,你可以在這裡定義當叠加層顯示時你想要的內容。
    • overlay 中,它檢查 isPresented.wrappedValue。如果為 true,它會顯示 FeedbackRatingView 並提供自定義的內容。
  3. 使用方法:

    最後,示例中使用了 .feedbackRatingAlert 方法。你將所有需要的綁定變數傳入,並在方法的主體中提供叠加層的內容。在這裡,你還沒有為其提供具體內容,只是開啟了這個叠加層。

總之,這些代碼讓你能夠在任何 SwiftUI view 上方輕鬆地添加一個自定義叠加層。當 isPresented 的值為 true 時,叠加層將顯示,並具有你在 FeedbackRatingView 中定義的樣式。


Refer:

利用 SwiftUI 的ViewBuilder 輕鬆創建複雜佈局和視圖層次結構
@ViewBuilder usage explained with code examples
Custom containers - a free Hacking with iOS: SwiftUI Edition tutorial


上一篇
Day 23: Data binding: @State, @Binding, read-only property
下一篇
Day 25: UIHostingController 🫸🏻🤏🏻 
系列文
SwiftUI 男孩30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言