I am working on a project where we have a UIViewRepresentable View in the background of a SwiftUI View, and the preferences for the foreground view are getting clobbered.
If I put the UIViewRepresentable View in the foreground (overlay), then preferences on the SwiftUI view are honored. If I use a native SwiftUI View in the background then the preferences are honored.
Consider this code:
import SwiftUI
struct ContentView: View {
var body: some View {
MyView()
.background() {
BackgroundView()
}
.onPreferenceChange(MyPreferenceKey.self) { value in
if let value {
print("-- preference changed: \(value)")
} else {
print("-- preference changed to `nil`")
}
}
}
}
struct MyView: View {
var body: some View {
Text("Hello")
.preference(key: MyPreferenceKey.self, value: "Hello World")
}
}
struct MyPreferenceKey: PreferenceKey {
static func reduce(value: inout String?, nextValue: () -> String?) {}
}
struct BackgroundView: UIViewRepresentable {
func makeUIView(context: Context) -> UIButton {
UIButton()
}
func updateUIView(_ uiView: UIButton, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator {
init() {}
}
}
BackgroundView is a UIViewRepresentable View. In this case the printed output is:
-- preference changed to `nil`
However, if you use .overlay instead of .background:
MyView()
.overlay {
BackgroundView()
}
Then it prints:
-- preference changed: Hello World
Which is what it should. Is there a way to workaround this?