62

我正在寻找一种方法来禁用 WKWebView 的 iOS 实现上的“捏缩放”放大手势。OS X 有一个可用的放大 BOOL 属性,但它似乎在 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;

我也试过查看 WKWebView 的手势识别器,但这似乎是一个空数组。我假设实际的识别器在组件的结构中埋藏得更深(从外观上看相当复杂),并且如果可能的话,宁愿不去挖掘它们。

我知道可能会禁用手势触发的可能黑客(选择性地将手势传递给 WebView,添加子视图以捕获捏手势等),但我总是发现那些会在事件中引入延迟并希望将实现保持为尽可能干净/无黑客攻击。

4

21 回答 21

80

您可以通过设置 WKWebKit 的 UIScrollView 的委托并按viewForZooming(in:)以下方式实现来防止用户缩放:

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
    }
}
于 2015-08-11T14:02:06.657 回答
49

我尝试过设置minimumZoomScalemaximumZoomScale属性UIScrollViewto1或to的isMultipleTouchEnabled属性或从调用中返回但没有奏效。在我的情况下,经过多次试验和错误,以下在我的情况下有效[在 iOS 10.3 上测试]:UIViewfalsenilviewForZooming(in:)UIScrollViewDelegate

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
   }
}
于 2017-04-04T11:04:31.453 回答
47

以下答案不再适用于 iOS 10 测试版。

为了提高 Safari 中网站的可访问性,即使网站在视口中设置了 user-scalable=no,用户现在也可以捏合缩放。


WKWebView 似乎以与 Mobile Safari 相同的方式尊重视口元标记(正如预期的那样)。因此,我发现在页面加载后通过 javascript 将该标签注入 DOM 就可以了。我会厌倦这个解决方案,除非你确切地知道什么 HTML 被加载到 webview 中,否则我怀疑它会产生意想不到的后果。就我而言,我正在加载 HTML 字符串,因此我可以将其添加到随应用程序提供的 HTML 中。

要对任何网页进行通用操作:

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

看看刚刚完成了什么样的导航可能是明智的,因为只有一个新页面需要执行这个 javascript。

于 2014-09-03T15:05:05.313 回答
24

在 Swift 中禁用 WkWebView 缩放的完整工作代码。

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)
    }
}
于 2018-05-03T12:43:51.327 回答
22

原生解决方案对我不起作用,注入 JS 也不理想。我注意到,当发生缩放并调用我的委托时,即使我在初始化 webview 时禁用了 pinchGestureRecognizer,也会启用它。为了解决这个问题,我在缩放开始时将其设置为禁用:

extension ViewController: UIScrollViewDelegate {

    // disable zooming in webview
    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        scrollView.pinchGestureRecognizer?.isEnabled = false
    }
}
于 2018-06-06T21:24:27.757 回答
15

Landschaft 的完整Swift 3 / iOS 10版本的回答:

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
    }
}
于 2017-03-02T16:25:33.790 回答
11

您可以为此使用 UIScrollViewDelegate。首先在 viewDidLoad() 或任何其他合适的方法中将委托分配给您的 webview:

class LoginViewController: UIViewController, WKUIDelegate, UIScrollViewDelegate {

  override func viewDidLoad() {
      webView.scrollView.delegate = self 
  }

  //Add this delegate method in your view controller
  func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
      scrollView.pinchGestureRecognizer?.isEnabled = false
  }
}
于 2017-12-08T14:13:27.937 回答
8

如果您显示本地 html,您可以修改此 html 并将此元标记放入您的 html:

<head>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
</head>
于 2018-07-17T14:41:28.117 回答
4

防止缩放的简单方法

override func viewDidLoad() {
    super.viewDidLoad()

    webView.scrollView.delegate = self
}

func scrollViewDidZoom(_ scrollView: UIScrollView) {

    scrollView.setZoomScale(1.0, animated: false)
}
于 2019-02-28T08:40:04.733 回答
3

斯威夫特 2.0

extension WKWebView {
    func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
        return nil
    }
}
于 2016-02-09T19:43:05.737 回答
2

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

}
于 2017-08-18T20:47:59.407 回答
2

如果您处理 html 中的链接并不重要(例如您只想显示文本),最简单的方法是关闭用户交互 webView.userInteractionEnabled = false

于 2016-07-13T09:36:57.040 回答
1

我没有足够的声誉来为答案添加评论,但我想提一下,Kevin 的解决方案(元视口)不再适用于 iOS 10 测试版。不过,Landschaft 的解决方案对我有用!

由于 JS 解决方案使用 W3C 标准,因此应该始终支持它。

啊,凯文,我希望这些事情是这样运作的。

更多信息:https ://stackoverflow.com/a/37859168/1389714

于 2016-07-11T17:15:26.837 回答
1

这是Gulshan Kumar的答案的略微修改版本,它在 iOS 12.1.2 中对我有用,它还可以防止由于双击和旋转而导致的缩放。在我的示例中,我只是将脚本直接注入到 Web 视图中。我将比例调整为 60%,在构建源字符串时无需使用连接。

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)
于 2018-12-31T18:45:09.650 回答
1

通过要求手势识别器失败来禁用双击以缩放手势。当用户双击时,它将阻止浏览器采取行动。

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

于 2018-05-18T10:04:34.130 回答
0

对于 obj-c.,添加UIScrollViewDelegate协议。

/* somewhere else, for example in viewDidLoad() */
_wkWeb.scrollView.delegate = self;

..

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
    scrollView.pinchGestureRecognizer.enabled = NO;
}
于 2021-09-07T12:35:48.060 回答
0

如果最好在网页加载完成时禁用 Pinch 缩放,它还可以指定要禁用哪个特定 URL

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

    print("finish")
} 
于 2019-02-22T00:52:41.353 回答
0

我工作的应用程序需要通过 Javascript 缩放视图。接受的答案也阻止了 JavaScript 从页面内部进行缩放。我只需要禁用应用程序用户的捏合手势。我找到的唯一解决方案是在页面加载后禁用 Web 视图的手势:

- (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;
        }
    }
}
于 2017-02-23T09:44:07.727 回答
0

我们需要在 XCode 8 中使用以下签名更改委托调用:

覆盖 func viewForZooming(in scrollView: UIScrollView) -> UIView? {返回零}

于 2016-12-09T00:13:48.317 回答
-1

这对我有用。https://gist.github.com/paulofierro/5b642dcde5ee9e86a130

  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)
  let userContentController: WKUserContentController = WKUserContentController()
  let conf = WKWebViewConfiguration()
  conf.userContentController = userContentController
  userContentController.addUserScript(script)
  let webView = WKWebView(frame: CGRect.zero, configuration: conf)
于 2018-04-19T02:43:49.883 回答
-3

如果 webview 是用于只读目的的用户,即仅用于显示 web 内容使用

webView.isUserInteractionEnabled = false

这样,缩放手势将不起作用。

于 2017-12-05T08:39:15.447 回答