I create UIScrollView
to be integrated inside SwiftUI view. It contains UIHostingController
to host SwiftUI view. When I update UIHostingController
, UIScrollView
does not change its constraints. I can scroll neither to top nor to bottom. When I try to call viewDidLoad()
inside updateUIViewController(_:context:)
, it works like I expect. Here is my sample code,
struct ContentView: View {
@State private var max = 100
var body: some View {
VStack {
Button("Add") { self.max += 2 }
ScrollableView {
ForEach(0..<self.max, id: \.self) { index in
Text("Hello \(index)")
.frame(width: UIScreen.main.bounds.width, height: 100)
.background(Color(red: Double.random(in: 0...255) / 255, green: Double.random(in: 0...255) / 255, blue: Double.random(in: 0...255) / 255))
}
}
}
}
}
class ScrollViewController<Content: View>: UIViewController, UIScrollViewDelegate {
var hostingController: UIHostingController<Content>! = nil
init(rootView: Content) {
self.hostingController = UIHostingController<Content>(rootView: rootView)
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var scrollView: UIScrollView = UIScrollView()
override func viewDidLoad() {
self.view = UIView()
self.addChild(hostingController)
view.addSubview(scrollView)
scrollView.addSubview(hostingController.view)
scrollView.delegate = self
scrollView.scrollsToTop = true
scrollView.isScrollEnabled = true
makeConstraints()
hostingController.didMove(toParent: self)
}
func makeConstraints() {
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
hostingController.view.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
hostingController.view.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
hostingController.view.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
}
}
struct ScrollableView<Content: View>: UIViewControllerRepresentable {
var content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
func makeUIViewController(context: Context) -> ScrollViewController<Content> {
let vc = ScrollViewController(rootView: self.content())
return vc
}
func updateUIViewController(_ viewController: ScrollViewController<Content>, context: Context) {
viewController.hostingController.rootView = self.content()
viewController.viewDidLoad()
}
}
I don't think it is a good way to do. I want to know if there is the best way to update controller. If anyone knows the best solution, share me please. Thanks.