I have some experience in SwiftUI, but am new to UIKit.
I'd like to import the zoom and position from one instance of an UIViewRepresentable UIKit ScrollView to another. So, basically, the user scrolls and zooms and later, in another branch of the view hierarchy, I want to start zoomed in at that zoom and position. I can't get it to work though, even after many attempts.
Below is my makeUIView function where I try to set the position and zoom that I want (after some initial setup).
func makeUIView(context: Context) -> UIScrollView {
// set up the UIScrollView
let scrollView = UIScrollView()
scrollView.delegate = context.coordinator
scrollView.bouncesZoom = true
scrollView.delaysContentTouches = false
scrollView.maximumZoomScale = 0.85 * screenScale * 10
scrollView.minimumZoomScale = 0.85 * screenScale
// create a UIHostingController to hold our SwiftUI content
let hostedView = context.coordinator.hostingController.view!
hostedView.translatesAutoresizingMaskIntoConstraints = true
hostedView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
hostedView.frame = scrollView.bounds
scrollView.addSubview(hostedView)
/*
Here I add the zoom and position
*/
scrollView.zoomScale = 0.85 * screenscale
// add zoom and content offset
if let zoomScale = zoomScale, let contentOffset = contentOffset {
scrollView.contentOffset = contentOffset
// make sure it is within the bounds
var newZoomScale = zoomScale
if zoomScale < scrollView.minimumZoomScale {
print("too small")
newZoomScale = scrollView.minimumZoomScale
} else if zoomScale > scrollView.maximumZoomScale {
print("too large")
newZoomScale = scrollView.maximumZoomScale
}
scrollView.setContentOffset(contentOffset, animated: true)
scrollView.setZoomScale(newZoomScale, animated: true)
}
return scrollView
}
The way I get the zoom and contentOffset in the first place is to grab the values from the Coordinator in first ScrollView instance using the below code. As far as I can tell this works well and I get updates with sensible values after zooming or scrolling. The first code snippet contains the makeCoordinator function where I initiate the coordinator with methods from an environmentObject (which then updates said object). The second snippet contains the Coordinator.
func makeCoordinator() -> Coordinator {
return Coordinator(hostingController: UIHostingController(rootView: self.content),
userScrolledAction: drawingModel.userScrollAction,
userZoomedAction: drawingModel.userZoomAction)
}
class Coordinator: NSObject, UIScrollViewDelegate {
var hostingController: UIHostingController<Content>
let userScrolledAction: (CGPoint) -> Void
let userZoomedAction: (CGFloat) -> Void
init(hostingController: UIHostingController<Content>, userScrolledAction: @escaping (CGPoint) -> Void, userZoomedAction: @escaping (CGFloat) -> Void) {
self.hostingController = hostingController
self.userScrolledAction = userScrolledAction
self.userZoomedAction = userZoomedAction
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return hostingController.view
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
userScrolledAction(scrollView.contentOffset)
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
userZoomedAction(scrollView.zoomScale)
}
}