简体   繁体   English

如何在 SwiftUI 中使用 CustomType 进行绑定,使我的视图停止不必要的渲染?

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

I have a CustomType called AppData , and it look like this:我有一个名为AppDataCustomType ,它看起来像这样:


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

I am using this AppData in my Views as State or Binding, I have 2 Views in my project called: ContentView and another one called BindingView .我在我的视图中使用这个AppData作为 State 或 Binding,我的项目中有2 个视图称为: ContentView和另一个称为BindingView In my BindingView I am just using Color information of AppData .在我的BindingView中,我只是使用AppData的颜色信息。 And I am expecting that my BindingView render or response for Color information changes!我期待我的BindingView呈现或响应颜色信息的变化! How ever in the fact BindingView render itself even for stringOfText Which is totally unnecessary, because that data is not used in View.实际上BindingView甚至会为stringOfText呈现自己,这是完全没有必要的,因为 View 中没有使用该数据。 I thought that maybe BindingView not just considering for colorOfText but also for all package that cary this data and that is appData So I decided help BindingView to understand when it should render itself, and I made that View Equatable , But that does not helped even.我认为也许BindingView不仅考虑colorOfText ,而且还考虑所有携带这些数据的 package ,即 appData 所以我决定帮助BindingView了解它应该何时呈现自己,并且我制作了 View Equatable ,但这甚至没有帮助。 Still BindingView refresh and render itself on changes of stringOfText which it is wasting of rendering.仍然BindingView在浪费渲染的stringOfText更改时刷新和渲染自身。 How can I solve this issue of unnecessary rendering while using CustomType as type for my State or Binding.在将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
    }

}

When using Equatable (and .equatable() , EquatableView() ) on Views , SwiftUI makes some decisions about when to apply our own == functions and when it is going to compare the parameters on its own.Views上使用Equatable (和.equatable()EquatableView() )时,SwiftUI 会做出一些决定,决定何时应用我们自己的==函数以及何时自行比较参数。 See another one of my answers with more details about this here: https://stackoverflow.com/a/66617961/560942在此处查看我的另一个答案以及更多详细信息: https://stackoverflow.com/a/66617961/560942

In this case, it appears that even if Equatable is declared, SwiftUI skips it because it must be deciding that the POD (plain old data) in the Binding is determined to be non-equal and therefore it's going to refresh the view (again, even though one would think that the == would be enough to force it not to).在这种情况下,似乎即使声明了Equatable , SwiftUI 也会跳过它,因为它必须确定Binding中的POD (普通旧数据)被确定为不相等,因此它将刷新视图(再次,即使有人会认为==足以迫使它不要这样做)。

In the example you gave, obviously it's trivial for the system to re-render the Text element, so it doesn't really matter if this re-render happened.在您给出的示例中,系统重新渲染Text元素显然是微不足道的,因此重新渲染是否发生并不重要。 But, in the even that there actually are consequences to re-rendering, you could encapsulate the non-changing parts into a separate child view:但是,即使重新渲染确实会产生后果,您也可以将不变的部分封装到单独的子视图中:

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)
    }
}

In the above code, although the BindingView is re-rendered each time (although at basically zero cost, because nothing will change), the new child view is skipped because its parameters are equatable (even without declaring Equatable).在上面的代码中,虽然每次都重新渲染BindingView (虽然成本基本为零,因为什么都不会改变),但是新的子视图被跳过了,因为它的参数是 equatable 的(即使没有声明 Equatable)。 So, in a non-contrived example, if the child view were expensive to render, this would solve the issue.因此,在一个非人为的示例中,如果子视图的渲染成本很高,这将解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何制作一个采用 Binding 并将其传递给视图中的另一个 Binding 的视图 - SwiftUI - How to make a view that takes a Binding and passes it to another Binding in the view - SwiftUI 如何停止所有SWIFTUI按钮一起切换? - How can I stop all my SWIFTUI buttons toggling together? 如何使我的自定义 ViewModifier 仅适用于 SwiftUI 中符合(可识别和视图)的内容/视图? - How can I make my custom ViewModifier works only on Contents/Views that conform (Identifiable and View) in SwiftUI? SwiftUI:如何将通知交互更改为视图的一部分? - SwiftUI: How can I make a notification interaction change part of my view? 如何让我的 CustomView 返回视图以及 SwiftUI 中的更多额外数据? - How can I make my CustomView returns View plus some more extra data in SwiftUI? 如何使用 SwiftuI 在 Apple Watch 上的初始视图 storyboard 左侧制作 storyboard? - How can I make a storyboard to the left of an initial view storyboard on Apple Watch using SwiftuI? 如何在 SwiftUI 的视图之外制作 State 包装器? - How can I make a State wrapper outside of View in SwiftUI? 如何在 SwiftUI 中为我的视图提供背景图像 - How can I give a background Image to my View in SwiftUI SwiftUI - 如何在我的视图中调用 Function? - SwiftUI - How can I call a Function in my View? 如何在视图中按比例缩放刻度? 斯威夫特 - How can I scale my ticks proportionally in view? Swiftui
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM