SwiftUI UIViewRepresentable ScrollView is not zooming

1k Views Asked by At

I am developing an iOS app using the SwiftUI. I need to implement the "pinch to zoom" feature in the app so i tried using the SwiftUI's ScrollView but went in to the problems of not able to pinch and drag the content at the same time as discussed in the question here. So i tried using the UIKit's UIScrollView in an UIViewRepresentable as suggested in the same thread. The problem i am facing now is when i pinch zoom the view the following error is displayed in the console and view doesn't zoom.

[Assert] -[UIScrollView _clampedZoomScale:allowRubberbanding:]: Must be called with non-zero scale

My UIViewRepresentable does not occupy the entire screen and is embedded in a VStack that occupies some portion on the screen along with other elements. I am using NavigationView that holds the VStack. I have an ObservableObject as a state on the main view. I update few @Published properties on this ObservableObject from .onAppear() of the main view. When i stop updating these properties, the zoom seems to be working as expected. I am not sure what is causing the issue, can some one please help if you have faced the above error? Thanks in advance.

I could replicate this with a sample code provided below.

TestScrollViewApp.swift

@main
struct TestScrollViewApp: App {
    var body: some Scene {
        WindowGroup {
            TestView(interactor: TestInteractor())
        }
    }
}

TestView.swift

import Foundation
import SwiftUI
struct TestView: View {
    @ObservedObject var interactor : TestInteractor
    var body: some View {
        ZStack{
            NavigationView{
                VStack{
                    Text("Hi there!")
                    HStack{
                        Text("HI i am beside map")
                        NativeScrollView()
                    }
                    Text("Hi I am footer!")
                }
            }.navigationViewStyle(StackNavigationViewStyle())
        }.onAppear{
                interactor.setUp()
        }
    }
}

struct NativeScrollView: UIViewRepresentable {
    let imageview = UIImageView()
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UIScrollViewDelegate {
        let parent: NativeScrollView
        var zoomableView: UIView?

        init(_ parent: NativeScrollView) {
            self.parent = parent
        }
        
        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            return zoomableView
        }
    }
    
    func makeUIView(context: Context) -> UIScrollView {
        let scrollView = UIScrollView()
        scrollView.delegate = context.coordinator
        scrollView.isScrollEnabled = true
        scrollView.bouncesZoom = true;
        imageview.contentMode = .scaleAspectFit
        imageview.autoresizingMask = [.flexibleWidth,.flexibleHeight]
        //add the image view
        imageview.image = UIImage(named: "mapscreen")
        scrollView.addSubview(imageview)
        scrollView.minimumZoomScale = 1.0
        scrollView.maximumZoomScale = 4.0
        return scrollView
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {
        context.coordinator.zoomableView = imageview
    }
}

TestInteractor.swift

class TestInteractor:ObservableObject{
    @Published var hasFooter = true
    
    func setUp(){
        hasFooter = false
    }
}
0

There are 0 best solutions below