簡體   English   中英

如何在 SwiftUI 中使用 CustomType 進行綁定,使我的視圖停止不必要的渲染?

[英]How can I make my View stop unnecessary rendering with using CustomType for Binding in SwiftUI?

我有一個名為AppDataCustomType ,它看起來像這樣:


struct AppData {
    var stringOfText: String
    var colorOfText: Color
}

我在我的視圖中使用這個AppData作為 State 或 Binding,我的項目中有2 個視圖稱為: ContentView和另一個稱為BindingView 在我的BindingView中,我只是使用AppData的顏色信息。 我期待我的BindingView呈現或響應顏色信息的變化! 實際上BindingView甚至會為stringOfText呈現自己,這是完全沒有必要的,因為 View 中沒有使用該數據。 我認為也許BindingView不僅考慮colorOfText ,而且還考慮所有攜帶這些數據的 package ,即 appData 所以我決定幫助BindingView了解它應該何時呈現自己,並且我制作了 View Equatable ,但這甚至沒有幫助。 仍然BindingView在浪費渲染的stringOfText更改時刷新和渲染自身。 在將CustomType用作 State 或 Binding 的類型時,如何解決這個不必要的渲染問題。


struct ContentView: View {

    @State private var appData: AppData = AppData(stringOfText: "Hello, world!", colorOfText: Color.purple)

    var body: some View {

        print("rendering ContentView")

        return VStack(spacing: 20) {

            Spacer()

            EquatableView(content: BindingView(appData: $appData))
            //BindingView(appData: $appData).equatable()

            Spacer()

            Button("update stringOfText from ContentView") { appData.stringOfText += " updated"}

            Button("update colorOfText from ContentView") { appData.colorOfText = Color.red }

            Spacer()

        }

    }
}

 struct BindingView: View, Equatable {

    @Binding var appData: AppData

    var body: some View {

        print("rendering BindingView")

        return Text("123")
            .bold()
            .foregroundColor(appData.colorOfText)

    }

    static func == (lhs: BindingView, rhs: BindingView) -> Bool {
        print("Equatable function used!")
        return lhs.appData.colorOfText == rhs.appData.colorOfText
    }

}

Views上使用Equatable (和.equatable()EquatableView() )時,SwiftUI 會做出一些決定,決定何時應用我們自己的==函數以及何時自行比較參數。 在此處查看我的另一個答案以及更多詳細信息: https://stackoverflow.com/a/66617961/560942

在這種情況下,似乎即使聲明了Equatable , SwiftUI 也會跳過它,因為它必須確定Binding中的POD (普通舊數據)被確定為不相等,因此它將刷新視圖(再次,即使有人會認為==足以迫使它不要這樣做)。

在您給出的示例中,系統重新渲染Text元素顯然是微不足道的,因此重新渲染是否發生並不重要。 但是,即使重新渲染確實會產生后果,您也可以將不變的部分封裝到單獨的子視圖中:

struct BindingView: View {
    @Binding var appData: AppData

    var body: some View {
        print("rendering BindingView")
        return BindingChildView(color: appData.colorOfText)
    }

    //no point in declaring == since it won't get called (at least with the current parameters
}

struct BindingChildView : View {
    var color: Color
    
    var body: some View {
        print("rendering BindingChildView")
        return Text("123")
            .bold()
            .foregroundColor(color)
    }
}

在上面的代碼中,雖然每次都重新渲染BindingView (雖然成本基本為零,因為什么都不會改變),但是新的子視圖被跳過了,因為它的參數是 equatable 的(即使沒有聲明 Equatable)。 因此,在一個非人為的示例中,如果子視圖的渲染成本很高,這將解決問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM