I’m trying to reuse a UIKit view on SwiftUI with a UIViewRepresentable.
Whenever i tap the representable i want to go to a fullScreenCover and reuse that same UIView.
Somehow, when i close the fullscreenView, the UIView is missing.
I’ve tried several approaches but i couldn’t make it work,
Can some one point me in the right direction, is there something i’m missing to see?
struct ContentView: View {
@State var isFullscreen: Bool = false
/// Array of UIView objects
var uiViewArray: [CustomUIView] = [CustomUIView(text: "1"), CustomUIView(text: "2"), CustomUIView(text: "3")]
let cardWidth: CGFloat = 200
let cardHeight: CGFloat = 200
@StateObject var viewManager = ViewManager()
var body: some View {
return VStack {
ScrollView {
ForEach(uiViewArray, id: .id) { uiView in
LabelViewRepresentable(customUIView: uiView)
.frame(width: cardWidth,
height: cardHeight)
.onTapGesture(count: 2) {
viewManager.selectedFullscreenView = uiView
isFullscreen.toggle()
}
}
}
}
.background(Color.gray)
.fullScreenCover(isPresented: $isFullscreen,
content: {
FullScreenView(isFullscreen: $isFullscreen,
uiView: viewManager.selectedFullscreenView)
})
}
}
struct FullScreenView: View {
@Binding var isFullscreen: Bool
var uiView: CustomUIView?
var body: some View {
VStack {
Button(action: {
isFullscreen.toggle()
}, label: {
Text("Close")
})
if uiView != nil {
LabelViewRepresentable(customUIView: uiView!)
}
}
}
}
struct LabelViewRepresentable: UIViewRepresentable {
var customUIView: CustomUIView
init(customUIView: CustomUIView) {
self.customUIView = customUIView
}
func makeUIView(context: Context) -> CustomUIView {
uiView.backgroundColor = .green
return customUIView
}
func updateUIView(_ uiView: CustomUIView, context: Context) { }
}
class CustomUIView: UIView {
var text: String
var id = UUID().uuidString
init(text: String) {
self.text = text
super.init(frame: .zero)
let label = UILabel()
label.frame = .init(origin: .zero,
size: CGSize(width: 100, height: 100))
label.text = self.text
self.addSubview(label)
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ViewManager: ObservableObject {
var selectedFullscreenView: CustomUIView?
}
2
Answers
The
UIView
can only be added once to a view hierarchy. Once it’s added to the full screen view, it’s taken out of the original hierarchy and it has no signal to add itself back in when the full screen view is dismissed.You can avoid this issue by conditionally displaying it in the original
ScrollView
. Note that I’ve added aSpacer
to take its space and preserve the scroll position while the realUIView
is omitted from the hierarchy.makeUIView
needs to init it, e.g.You also need to implement
updateUIView
to use the struct’s vars to update theuiView
with any changes, e.g.Think of the
UIViewRepresentable
like a configuration value that constantly changes and you use to update the sameUIView
object. SwiftUI keeps track of whatUIView
object to configure based on its position in theView
hierarchy (called its identity) and passes it in toupdateUIView
so you don’t need to hold onto it yourself.