Add a preference key to NSViewPepresentable/UIViewRepresentable in SwiftUI

Viewed 404

I have an instance of a custom AppKit/UIKit view, wrapped into an **ViewRepresentable that needs to communicate some diagnostic information up the SwiftUI hierarchy. Since this information is not of primary importance, I would like to use the PreferenceKey API to do it, so that parent views can subscribe to it only when needed. Unfortunately, I can't figure a way to set a preference key on my view, since I don't have assess to the view struct itself and thus can't use the preference() API. Is there some way how I can set the preference key from the coordinator?

1 Answers

Here is a simple demo of possible approach. Tested with Xcode 12 / iOS 14. The idea is to construct UIViewRepresentable with injected preference key.

struct DemoView: View {
    @State private var diag = CGFloat.zero
    var body: some View {
        VStack {
            Text("Diagnostic >> \(diag)")
                .background(MyUIRep.trackingRep)
        }
        .onPreferenceChange(MyPrefKey.self) { value in
            self.diag = value
        }
    }
}

struct TestPreferenceKeyInRep_Previews: PreviewProvider {
    static var previews: some View {
        TestPreferenceKeyInRep()
    }
}

struct MyUIRep: UIViewRepresentable {
    static var trackingRep: some View {
        MyUIRep().preference(key: MyPrefKey.self, value: 13.31)
    }

    func makeUIView(context: Context) -> UIView {
        return UIView()
    }

    func updateUIView(_ uiView: UIView, context: Context) {
    }

}

struct MyPrefKey : PreferenceKey {
    static var defaultValue: CGFloat = .zero

    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value += nextValue()
    }
}
Related