繁体   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