Skip to content

Instantly share code, notes, and snippets.

@timothycosta
Created July 5, 2019 03:25
Show Gist options
  • Save timothycosta/0d8f64afeca0b6cc29665d87de0d94d2 to your computer and use it in GitHub Desktop.
Save timothycosta/0d8f64afeca0b6cc29665d87de0d94d2 to your computer and use it in GitHub Desktop.
UIScrollView wrapped for SwiftUI
//
// UIScrollViewWrapper.swift
// lingq-5
//
// Created by Timothy Costa on 2019/07/05.
// Copyright © 2019 timothycosta.com. All rights reserved.
//
import SwiftUI
struct UIScrollViewWrapper<Content: View>: UIViewControllerRepresentable {
var content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
func makeUIViewController(context: Context) -> UIScrollViewViewController {
let vc = UIScrollViewViewController()
vc.hostingController.rootView = AnyView(self.content())
return vc
}
func updateUIViewController(_ viewController: UIScrollViewViewController, context: Context) {
viewController.hostingController.rootView = AnyView(self.content())
}
}
class UIScrollViewViewController: UIViewController {
lazy var scrollView: UIScrollView = {
let v = UIScrollView()
v.isPagingEnabled = true
return v
}()
var hostingController: UIHostingController<AnyView> = UIHostingController(rootView: AnyView(EmptyView()))
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.scrollView)
self.pinEdges(of: self.scrollView, to: self.view)
self.hostingController.willMove(toParent: self)
self.scrollView.addSubview(self.hostingController.view)
self.pinEdges(of: self.hostingController.view, to: self.scrollView)
self.hostingController.didMove(toParent: self)
}
func pinEdges(of viewA: UIView, to viewB: UIView) {
viewA.translatesAutoresizingMaskIntoConstraints = false
viewB.addConstraints([
viewA.leadingAnchor.constraint(equalTo: viewB.leadingAnchor),
viewA.trailingAnchor.constraint(equalTo: viewB.trailingAnchor),
viewA.topAnchor.constraint(equalTo: viewB.topAnchor),
viewA.bottomAnchor.constraint(equalTo: viewB.bottomAnchor),
])
}
}
@dz902
Copy link

dz902 commented Apr 13, 2024

Works great, just that if I put VStack in, VStack width is bound to its content and not greedy.

@mysterytoy
Copy link

I'm having the same issue with the content height. Anybody get it working?

@wilg Did you ever get this working?

@wilg
Copy link

wilg commented Apr 17, 2024

no, sorry

@mirkobraic
Copy link

mirkobraic commented Jul 29, 2024

@mysterytoy @wilg I solved the issue on a similar component of mine by adding hostingController.sizingOptions = .intrinsicContentSize in the UIScrollViewViewController initializer.
Edit: Here is an excellent article about it: https://medium.com/@batrakov.vitaly/adapting-uihostingcontroller-to-changes-in-swiftui-view-size-da11a0994a1e

@EngOmarElsayed
Copy link

one more thing layoutIfNeeded must be called before returing the view because otherwise the view may freeze when updating the content in the scrollView

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment