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?
}
>Solution :
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 a Spacer
to take its space and preserve the scroll position while the real UIView
is omitted from the hierarchy.
ForEach(uiViewArray, id: \.id) { uiView in
Group {
if !isFullscreen {
LabelViewRepresentable(customUIView: uiView)
} else {
Spacer()
}
}
.frame(width: cardWidth,
height: cardHeight)
.onTapGesture(count: 2) {
viewManager.selectedFullscreenView = uiView
isFullscreen.toggle()
}
}