web-dev-qa-db-fra.com

Désactiver le geste d'agrandissement dans WKWebView

Je cherche un moyen de désactiver le geste d'agrandissement "pincer pour zoomer" sur l'implémentation iOS de WKWebView. Une propriété de grossissement BOOL est disponible pour OS X, mais elle ne semble pas être disponible sur 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;

J'ai aussi essayé de regarder les dispositifs de reconnaissance de geste de WKWebView, mais cela semble afficher un tableau vide. Je suppose que les identifiants sont plus profonds dans la structure du composant (assez complexe, à en juger par son apparence) et préfèrent ne pas aller les chercher si possible.

Je connais des hacks qui pourraient potentiellement empêcher le geste de se déclencher (en passant de manière sélective à la WebView, en ajoutant une vue enfant pour capturer le geste de pincement, etc.), mais j'ai toujours trouvé que ceux-ci introduisaient un décalage dans l'événement et souhaitaient conserver la mise en œuvre nettoyer/bidouiller autant que possible.

47
Kevin

Vous pouvez empêcher vos utilisateurs d'effectuer un zoom en définissant le délégué de UIScrollView de votre WKWebKit et en implémentant viewForZooming(in:) comme suit:

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

La réponse ci-dessous ne fonctionne plus sous iOS 10 bêta. 

Pour améliorer l'accessibilité sur les sites Web dans Safari, les utilisateurs peuvent maintenant pincer pour zoomer même lorsqu'un site Web définit user-scalable = no dans le fichier fenêtre d'affichage.


WKWebView semble respecter la balise méta de la fenêtre d'affichage de la même manière que Mobile Safari (comme il fallait s'y attendre). Donc, j'ai trouvé que l'intrusion de cette balise dans le DOM par le biais de javascript après le chargement d'une page faisait l'affaire. Je serais fatigué de cette solution à moins que vous ne sachiez exactement quel code HTML est chargé dans la visualisation Web, sans quoi cela pourrait avoir des conséquences inattendues. Dans mon cas, je charge des chaînes HTML, je peux donc simplement les ajouter au code HTML fourni avec l'application.

Pour le faire génériquement pour toute page Web:

- (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];
}

Il serait peut-être sage de regarder quel type de navigation vient d’être complété, car seule une nouvelle page nécessitera l’exécution de ce javascript. 

38
Kevin

J'ai essayé de définir les propriétés minimumZoomScale et maximumZoomScale de UIScrollView sur les propriétés 1 ou isMultipleTouchEnabled de UIView à false ou de renvoyer nil en invoquant viewForZooming(in:) de UIScrollViewDelegate, mais aucune solution n'a fonctionné. Dans mon cas, après plusieurs essais et erreurs, ce qui suit fonctionne dans mon cas [testé sur 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
   }
}
20
yohannes

Full Swift 3/iOS 10 version de la réponse de Landschaft:

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;
    }
}
14
Simon Epskamp

Les solutions natives ne fonctionnaient pas pour moi et l'injection de JS n'est pas idéale. J'ai remarqué que lorsqu'un zoom se produit et que mon délégué est appelé, le pinchGestureRecognizer est activé même si je l'ai désactivé lors de l'initialisation de la vue Web. Pour résoudre ce problème, je le désactive au démarrage d'un zoom:

extension ViewController: UIScrollViewDelegate {

    // disable zooming in webview
    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        scrollView.pinchGestureRecognizer?.isEnabled = false
    }
}
12
pulse4life

Code de travail complet pour désactiver le zoom dans WkWebView dans Swift  

importer UIKit importer WebKit

classe ViewController: UIViewController, WKUIDelegate {

// @IBOutlet var eventWkWebView: WKWebView!

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()
    // Do any additional setup after loading the view, typically from a nib.
    //  view.addSubview(eventWkWebView)


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

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

}

}

9
Gulshan Kumar

Si vous affichez un code HTML local, vous pouvez simplement modifier ce code et mettre cette balise META dans votre code HTML:

<head>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
</head>
4
Leszek Szary

Vous pouvez utiliser UIScrollViewDelegate pour cela. Affectez d’abord un délégué à votre vue Web dans viewDidLoad () ou toute autre méthode appropriée comme suit:

class LoginViewController: UIViewController, WKUIDelegate, UIScrollViewDelegate {
  override func viewDidLoad() {
  webView.scrollView.delegate = self 
  }

 //And add this delegate method in your controller: 

  func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
  scrollView.pinchGestureRecognizer?.isEnabled = false
  scrollView.panGestureRecognizer.isEnabled = false
  }
}
3
Yakup Ad

Swift 2.0

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

voici comment j'ai désactivé le zoom pour Swift3 contrôleur de vue pour application one-webview-only

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

}
2
godblessstrawberry

S'il n'est pas important pour vous de gérer les liens en HTML (par exemple, vous souhaitez afficher uniquement du texte), le plus simple serait de désactiver l'interaction utilisateur webView.userInteractionEnabled = false

1
lvp

Désactivez le double-clic pour zoomer sur le geste en exigeant l'échec de la reconnaissance de geste. Cela empêchera le navigateur d’agir lorsque l’utilisateur tapera deux fois.

import UIKit

class DisableDoubleTapRecognizer : UITapGestureRecognizer, UIGestureRecognizerDelegate{
    override init(target: Any?, action: Selector?) {
        super.init(target: target, action: action)
    }
    
    init() {
        super.init(target:nil, action: nil)
        self.numberOfTapsRequired = 2;
        self.delegate = self;
    }
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true;
    }
}

//in your view controller
override func viewDidLoad() {
        super.viewDidLoad()
        
        webView.addGestureRecognizer(DisableDoubleTapRecognizer())
    }

1
user3543806

Je n'ai pas assez de réputation pour ajouter des commentaires aux réponses, mais je voulais mentionner que la solution de Kevin (méta-vue) ne fonctionne plus dans iOS 10 beta. La solution de Landschaft fonctionne pour moi, cependant!

Étant donné que la solution JS utilise les normes W3C, elle devrait toujours être prise en charge.

Ah, Kevin, j'aimerais que ce soit ainsi que fonctionnent ces choses.

Plus ici: https://stackoverflow.com/a/37859168/1389714

1
mark

Un moyen simple d'empêcher le zoom

override func viewDidLoad() {
    super.viewDidLoad()

    webView.scrollView.delegate = self
}

func scrollViewDidZoom(_ scrollView: UIScrollView) {

    scrollView.setZoomScale(1.0, animated: false)
}
0
Waqar Ahmed

Voici une version légèrement modifiée de la réponse de Gulshan Kumar qui a fonctionné pour moi dans iOS 12.1.2 et qui empêche également le zoom dû aux tapotements doubles et à la rotation. Dans mon exemple, je viens d’injecter le script directement dans la vue Web. J'ai ajusté l'échelle à 60%, et il n'est pas nécessaire d'utiliser la concaténation pour créer la chaîne source.

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

let script = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: true)

webView.configuration.userContentController.addUserScript(script)
0
Scott Gardner

S'il est préférable de désactiver le zoom pincement lorsque le chargement de la page Web est terminé, vous pouvez également spécifier l'URL à désactiver

public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
     if let url = webView.url, url.absoluteString == "***" {                       
        webView.scrollView.pinchGestureRecognizer?.isEnabled = false
     }

    print("finish")
} 
0
Jin

Nous devons modifier l'appel du délégué avec les signatures suivantes dans XCode 8:

remplacez func viewForZooming (dans scrollView: UIScrollView) -> UIView? { retourner nil }

0
Brianster

Si la vue Web est utilisateur à des fins de lecture seule, c’est-à-dire uniquement pour afficher l’utilisation du contenu Web

webView.isUserInteractionEnabled = false

De ce fait, le geste de zoom ne fonctionnera pas.

0
Sameer Bhide