Search code examples
iosswiftuiwebview

Swift - Add UIImageView as subview of UIWebView scrollView and scaling


I have a UIWebView and I have successfully added a UIImage view to the UIWebView’s scrollView like so:

let localUrl = String(format:"%@/%@", PDFFilePath, fileNameGroup)
        let url = NSURL.fileURLWithPath(localUrl)

        panRecognizer = UITapGestureRecognizer(target: self, action: #selector(panDetected))
        pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(pinchDetected))

        panRecognizer.delegate = self
        pinchRecognizer.delegate = self

        webview = UIWebView()
        webview.frame = self.view.bounds
        webview.scrollView.frame = webview.frame

        webview.userInteractionEnabled = true
        webview.scalesPageToFit = true
        webview.becomeFirstResponder()
        webview.delegate = self
        webview.scrollView.delegate = self
        self.view.addSubview(webview)
        webview.loadRequest(NSURLRequest(URL:url))
        webview.gestureRecognizers = [pinchRecognizer, panRecognizer]

let stampView:StampAnnotation = StampAnnotation(imageIcon: UIImage(named: "approved.png"), location: CGPointMake(currentPoint.x, currentPoint.y))
            self.webview.scrollView.addSubview(stampView)

My UIWebView scrollView is scalable. Now I am looking for away to have my UIImageView (StampAnnotation is a class and UIImageView is its subclass) scale when the scrollView scales. So if the user zooms in on the scrollView, the UIImageView will get bigger and stay in a fixed position and if the user zooms out, the UIImageView will get smaller while the scrollView gets smaller while staying in a fixed position.

I really hope that makes sense. I have tried the following:

func pinchDetected(recognizer:UIPinchGestureRecognizer)
    {

        for views in webview.scrollView.subviews
        {
            if(views.isKindOfClass(UIImageView))
            {
                views.transform = CGAffineTransformScale(views.transform, recognizer.scale, recognizer.scale)
                recognizer.scale = 1
            }
        }

        if(appDelegate.annotationSelected == 0)
        {
            webview.scalesPageToFit = true
        }
        else
        {
            webview.scalesPageToFit = false
        }

    }

but this does nothing, if I remove this line:

recognizer.scale = 1

it scales way too big too fast. My question is, how do I get my UIImageView to scale when the UIWebview’s scrollView scrolls?

Any help would be appreciated.

This solved my problem.

func scrollViewDidZoom(scrollView: UIScrollView) {

    for views in webview.scrollView.subviews
    {
        if(views.isKindOfClass(UIImageView))
        {
            views.transform = CGAffineTransformMakeScale(scrollView.zoomScale, scrollView.zoomScale)
        }
    }

}

No it does not stay in a fixed position on the page, but I think that is a constraints issue?


Solution

  • You were close...

    1) Add a property to hold onto an external reference for your stampViewFrame:

    var stampViewFrame = CGRect(x: 100, y: 100, width: 100, height: 100)
    

    2) Replace your scrollViewDidZoom() with this:

     func scrollViewDidZoom(scrollView: UIScrollView) {
        for views in webView.scrollView.subviews
        {
            if(views.isKindOfClass(UIImageView))
            {
                views.frame = CGRect(x: stampViewFrame.origin.x * scrollView.zoomScale, y: stampViewFrame.origin.y * scrollView.zoomScale, width: stampViewFrame.width * scrollView.zoomScale, height: stampViewFrame.height * scrollView.zoomScale)
            }
        }
    }
    

    3) Finally, because the zoom scale resets to 1 at the begining of each new zooming action, you need to adjust the value of your stampViewFrame property:

    func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {
        stampViewFrame = CGRect(x: stampViewFrame.origin.x * scale, y: stampViewFrame.origin.y * scale, width: stampViewFrame.width * scale, height: stampViewFrame.height * scale)
    }
    

    I also tried to answer your other question about layout during orientation change, but I now have a much better understanding of what you are trying to do. If you want your stampView to always be on in the same place relative to the web content, you have to get into HTML/JS because the webpage lays itself out dynamically. A much much more simple (and hopefully close enough) solution would be to add the following:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        webView.frame = view.bounds
        stampView.frame = stampViewFrame
    }