Disable magnification gesture in WKWebView

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

  • iOS: evaluateJavaScript will not invoke function when parameter contains newline character
  • WKWebView fails to load images and CSS using loadHTMLString(_, baseURL:)
  • Universal links not working with WKWebView
  • How to determine the content size of a WKWebView?
  • how do I get WKWebView to work in swift and for an macOS App
  • Can't set headers on my WKWebView POST request
  • #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.

    12 Solutions Collect From Internet About “Disable magnification gesture in WKWebView”

    You can prevent your users from zooming by setting the delegate of your WKWebKit’s UIScrollView and implementing the following method:

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

    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, 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.

    Full Swift 3 / iOS 10 version of Landschaft’s answer:

    import UIKit
    import WebKit
    
    class MyViewController: UIViewController, UIScrollViewDelegate {
    
        var webView = WKWebView()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.view.addSubview(webView)
            webView.scrollView.delegate = self
        }
    
        // Disable zooming in webView
        func viewForZooming(in: UIScrollView) -> UIView? {
            return nil;
        }
    }
    

    Swift 2.0

    extension WKWebView {
        func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
            return nil
        }
    }
    

    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
       }
    }
    

    I don’t have enough reputation to add comments to answers, but I wanted to mention that Kevin’s solution (meta viewport) no longer works in iOS 10 beta. Landschaft’s solution is working for me, though!

    Since the JS solution uses W3C standards, it should always be supported.

    Ah, Kevin, I wish that were how these things worked.

    More here: https://stackoverflow.com/a/37859168/1389714

    We need to change the delegate call with following signatures in XCode 8:

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

    this is how I disabled zoom for Swift3 view controller for one-webview-only app

    import UIKit
    import WebKit
    
    class ViewController: UIViewController, WKNavigationDelegate, UIScrollViewDelegate {
    
        @IBOutlet var webView: WKWebView!
    
        override func loadView() {
            webView = WKWebView()
            webView.navigationDelegate = self
            view = webView
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            webView.scrollView.delegate = self
        }
    
        func viewForZooming(in: UIScrollView) -> UIView? {
            return nil;
        }    
    
    }
    

    If it’s not important for you to handle links inside html (say you want to display text only) the simplest would be to turn off user interaction
    webView.userInteractionEnabled = false

    The application I work on needed the view to be zoomed by Javascript. The accepted answer blocked zooming by JavaScript from inside the page too.
    I only needed to disable pinch gesture by the user of the appliction. The only solution I’ve found is to disable the gesture of the web view after the page has loaded:

    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
        /* disable pinch gesture recognizer to allow zooming the web view by code but prevent zooming it by the user */
        for (UIGestureRecognizer *gr in self.webView.scrollView.gestureRecognizers) {
            if ([gr isKindOfClass:[UIPinchGestureRecognizer class]]) {
                gr.enabled = NO;
            }
        }
    }
    

    I used this one in Swift 3 iOS 10.3

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

    Solution without ScrollView delegate implementation:

    webView.scrollView.minimumZoomScale = 1
    webView.scrollView.maximumZoomScale = 1