jjrscott

Add a preference key to NSViewPepresentable/UIViewRepresentable in SwiftUI

Stack Overflow:

It is possible to achieve by embedding a private UIViewRepresentable in a View and using State/Binding to enable “upward” communication.

Here I have modified Asperi’s answer to show the preference key being set via a Binding.

As a possible aside, I’ve found it good practice to almost always embed my UIViewRepresentable in a View to avoid UIKit “leaking” into my SwiftUI code.

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

struct MyUIRep: View {
    @State private var myPrefKeyValue = CGFloat.zero

    var body: some View {
        _MyUIRep(myPrefKeyValue: $myPrefKeyValue)
            .preference(key: MyPrefKey.self, value: myPrefKeyValue)
    }
    
    private struct _MyUIRep: UIViewRepresentable {
        @Binding var myPrefKeyValue: CGFloat

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

        func updateUIView(_ uiView: UIView, context: Context) {
            DispatchQueue.main.async {
                myPrefKeyValue = 13.31
            }
        }
    }
}

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

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