-
-
Save timothycosta/0d8f64afeca0b6cc29665d87de0d94d2 to your computer and use it in GitHub Desktop.
// | |
// 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), | |
]) | |
} | |
} | |
I don't really recommend this approach anymore. If you want access to the underlying UIScrollView
that SwiftUI.ScrollView
uses, I would recommend using something like Introspect.
hi how would you use this to scroll to a particular index? can we set the offset manually?
To anyone that might be using this and found that the subviews added appear on a white background: You just need to add the following line before returning in makeUIViewController
:
vc.hostingController.view.backgroundColor = .clear
When using SwiftUI with tvOS, a ScrollView with a big Text View will not scroll. At least for me it didn't. I used this and added this v.panGestureRecognizer.allowedTouchTypes = [NSNumber(value: UITouch.TouchType.indirect.rawValue)]
after let v = UIScrollView()
and it started working. Many thanks!
@timothycosta
I fixed the height gap issue for the full height by adjusting the spacing of the VStack to 0:
GeometryReader { proxy in UIScrollViewWrapper { VStack(spacing: 0) { // <--- here ForEach(0..<100, id: \.self) { obj in ZStack { Color.purple Text("\(obj)") } .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) } } .frame(width: proxy.size.width) .background(Color.blue.opacity(0.25)) } .ignoresSafeArea() }
Works great, just that if I put VStack in, VStack width is bound to its content and not greedy.
I'm having the same issue with the content height. Anybody get it working?
@wilg Did you ever get this working?
no, sorry
@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
one more thing layoutIfNeeded must be called before returing the view because otherwise the view may freeze when updating the content in the scrollView
I ran into the same issue. Does somebody know how to fix that?