Disable magnification gesture in WKWebView

51,275

Solution 1

You can prevent your users from zooming by setting the delegate of your WKWebKit's UIScrollView and implementing viewForZooming(in:) as in the following:

class MyClass {
    let webView = WKWebView()

    init() {
        super.init()
        webView.scrollView.delegate = self
    }

    deinit() {
        // Without this, it'll crash when your MyClass instance is deinit'd
        webView.scrollView.delegate = nil
    }
}

extension MyClass: UIScrollViewDelegate {
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return nil
    }
}

Solution 2

I have tried setting minimumZoomScale and maximumZoomScale properties of UIScrollView to 1 or isMultipleTouchEnabled property of UIView to false or returning nil from invoking viewForZooming(in:) of UIScrollViewDelegate but none worked. In my case, after several trial and error, the following works in my case [Tested on iOS 10.3]:

class MyViewController: UIViewController {
   var webView: WKWebView?

   override viewDidLoad() {
      super.viewDidLoad()

      //...
      self.webView.scrollView.delegate = self
      //...
   }
}

extension MyViewController: UIScrollViewDelegate { 
   func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
      scrollView.pinchGestureRecognizer?.isEnabled = false
   }
}

Solution 3

The below answer no longer works in iOS 10 beta.

To improve accessibility on websites in Safari, users can now pinch-to-zoom even when a website sets user-scalable=no in the viewport.


WKWebView seems to respect the viewport meta tag the same way Mobile Safari does (as to be expected). So, I found injecting that tag into the DOM through javascript after a page load does the trick. I would be weary of this solution unless you know exactly what HTML is being loaded into the webview, otherwise I suspect it would have unintended consequences. In my case, I'm loading HTML strings, so I can just add it to the HTML I ship with the app.

To do it generically for any webpage:

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    NSString *javascript = @"var meta = document.createElement('meta');meta.setAttribute('name', 'viewport');meta.setAttribute('content', 'width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no');document.getElementsByTagName('head')[0].appendChild(meta);";
    
    [webView evaluateJavaScript:javascript completionHandler:nil];
}

It might be wise to take a look at what kind of navigation has just been completed, since only a new page will need this javascript executed.

Solution 4

Complete working code to disable zooming in WkWebView in Swift.

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate {
    var webView : WKWebView!

    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration:webConfiguration)
        webView.uiDelegate = self

        let source: String = "var meta = document.createElement('meta');" +
            "meta.name = 'viewport';" +
            "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
            "var head = document.getElementsByTagName('head')[0];" + "head.appendChild(meta);";

        let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
        webView.configuration.userContentController.addUserScript(script)

        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let myUrl = URL(string: "https://www.google.com")

        let myRequest = URLRequest(url: myUrl!)
        webView.load(myRequest)
    }
}

Solution 5

The native solutions were not working for me, and injecting JS is not ideal. I noticed that when a zoom occurs and my delegate is called, the pinchGestureRecognizer is enabled even though I disabled it when initializing the webview. To fix this, I set it to disabled whenever a zoom starts:

extension ViewController: UIScrollViewDelegate {

    // disable zooming in webview
    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        scrollView.pinchGestureRecognizer?.isEnabled = false
    }
}
Share:
51,275
Kevin
Author by

Kevin

Professional iOS developer, amateur just about everything else.

Updated on September 08, 2021

Comments

  • Kevin
    Kevin almost 3 years

    I'm looking for a way to disable the "pinch to zoom" magnification gesture on the iOS implementation of WKWebView. There is a magnification BOOL property available for OS X but it doesn't seem to be available on iOS.

    WKWebView.h

    #if !TARGET_OS_IPHONE
    /* @abstract A Boolean value indicating whether magnify gestures will
     change the web view's magnification.
     @discussion It is possible to set the magnification property even if
     allowsMagnification is set to NO.
     The default value is NO.
     */
    @property (nonatomic) BOOL allowsMagnification;
    

    I've, also, tried look at the WKWebView's gesture recognizers but that seems to be turning up an empty array. I'm assuming the actual recognizers are bured deeper in the component's structure (fairly complex, by the looks of it) and would rather not go digging for them if at all possible.

    I know of possible hacks that could potentially disable the gesture from firing (selectively passing gestures to the WebView, add child view to capture pinch gesture, etc) but I've always found those introduce lag into the event and want to keep the implementation as clean/hack free as possible.