【问题标题】:Disable magnification gesture in WKWebView在 WKWebView 中禁用放大手势
【发布时间】:2014-10-22 14:32:14
【问题描述】:

我正在寻找一种方法来禁用 WKWebView 的 iOS 实现上的“捏缩放”放大手势。 OS X 有一个 magnification 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、添加子视图以捕获捏合手势等),但我一直发现那些会在事件中引入延迟并希望保留实现尽可能干净/无黑客。

【问题讨论】:

    标签: ios webkit ios8 wkwebview


    【解决方案1】:

    您可以通过设置 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
        }
    }
    

    【讨论】:

    • 不要忘记添加对UIScrollViewDelegate的一致性,设置webView.scrollView.delegate = self;并取消deinit中的委托指针。
    • 这应该是正确的答案。一个原生的 iOS 解决方案,而不是尝试注入 JS。
    • 我不同意。虽然原生解决方案是理想的,但我认为这个解决方案与 JS 解决方案一样笨拙,并且可能更脆弱。虽然 WKWebView 提供 UIScrollView,但内部使用的是 WKScrollView。虽然它是 UIScrollView 的子类,但它忽略/覆盖了许多标准行为(其中之一是 contentInset)。缩放 HTML 文档与缩放 UIView 非常不同,因此我可以看到这种变化/不再起作用的未来。由于 JS 解决方案使用 W3C 标准,因此应该始终支持它。
    • @Prcela 不需要取消委托。这是一个弱变量,因此不会创建保留周期。
    • 将函数名称更新为“viewForZooming”(在 iOS10、iOS11 中),根据此问题的一些最新答案(在此页面上)
    【解决方案2】:

    我尝试将UIScrollViewminimumZoomScalemaximumZoomScale 属性设置为1UIViewisMultipleTouchEnabled 属性设置为false 或通过调用@98765 的@9876543329@ 返回nil但没有一个工作。在我的情况下,经过多次试验和错误,以下在我的情况下有效 [在 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
       }
    }
    

    【讨论】:

    • 谢谢!这正是我想要的。接受的答案不适用于我的情况,因为在委托中返回 nil 后,我的网页的比例是错误的。
    • 完美!使用这个,你可以通过 JS 改变图片框架,没有任何不良影响。
    • 我像你一样尝试了所有选项。你的回答对我来说很完美。谢谢:)
    • 注意:当用户界面方向改变时,通过实现 viewWillTransition 来避免缩放问题: override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // 旋转前 coordinator.animate(alongsideTransition: { context in // 旋转期间 }, completion: { context in // 旋转后 webView.scrollView.setZoomScale(webView.scrollView.minimumScale, animated: false) }) }
    • 仍然与 iOS 15 完美兼容。
    【解决方案3】:

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

    为了提高 Safari 中网站的可访问性,用户现在可以 即使网站在 视口。


    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。

    【讨论】:

    • 这仍然允许双击缩放。 minimum-scale=1.0 需要设置以避免这种情况。
    • 这个答案有帮助,但我似乎仍然能够创建可以缩放的情况。还不确定是什么或如何。
    • 这是正确的答案——不要弄乱 WKWebView 的 UIScrollView 委托。
    • 谢谢!将此与 Turbolinks 一起使用,并且似乎可以完美运行(在 iOS 11 上)。既不能捏合也不能双击放大。
    • 使用 userScripts 可能更容易做到这一点:stackoverflow.com/a/41741125/1683141
    【解决方案4】:

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

    【讨论】:

    • 唯一适用于我 iOS 11.4 的解决方案。我不知道为什么其他解决方案,尤其是本机解决方案不起作用,但 javascript 技巧却起作用了……在 Android 上开发多么容易,在 iOS 上开发多么困难。编程应该很简单吧?
    • 您的解决方案不适用于给定的网址 pdf995.com/samples/pdf.pdf 。如果您有任何解决方案,请帮助我。
    【解决方案5】:

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

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

    【讨论】:

    【解决方案6】:

    完整的 Swift 3 / iOS 10 版本 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
        }
    }
    

    【讨论】:

      【解决方案7】:

      您可以为此使用 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
        }
      }
      

      【讨论】:

      • 这个在 iOS 12 上对我有用。其他解决方案,如 viewport 或 return nil for viewForZooming 没有
      • 这个解决方案是iOS13的一个很好的起点!我唯一缺少的是在 HTML 中设置 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>,因为当手机的旋转发生变化时,应用内的视图正在缩放。
      【解决方案8】:

      如果你显示一个本地 html,你可以修改这个 html 并将这个 meta 标签放到你的 html 中:

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

      【讨论】:

        【解决方案9】:

        防止缩放的简单方法

        override func viewDidLoad() {
            super.viewDidLoad()
        
            webView.scrollView.delegate = self
        }
        
        func scrollViewDidZoom(_ scrollView: UIScrollView) {
        
            scrollView.setZoomScale(1.0, animated: false)
        }
        

        【讨论】:

          【解决方案10】:

          Swift 2.0

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

          【讨论】:

          • 请注意,所有 WKWebViews 都会这样做
          • 如果您先将其子类化并将扩展应用于子类,则不会。为我工作。
          • @Luke 并具有本地副作用,您可以将其放置在视图控制器文件范围内并将其标记为私有`私有扩展 WKWebView { func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? { 返回零 } } `
          【解决方案11】:

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

          【讨论】:

          • 这将禁用 url 点击
          • 因此我写了“如果处理 html 中的链接对您来说不重要”
          • 这将禁用滚动! OP想要禁用捏缩放,但我猜他想要一个可用的网络视图。
          【解决方案12】:

          这就是我为 one-webview-only app

          禁用 Swift3 视图控制器的缩放的方式
          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;
              }    
          
          }
          

          【讨论】:

          • 终于!伙计,很难追踪不断的 Swift 变化(网络上几乎所有其他东西的委托函数都是“viewForZoomingInScrollView”。感谢对“viewForZooming”的更新
          【解决方案13】:

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

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

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

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

          【讨论】:

          • 求助。就这样吧,我想。更改正确答案,感谢您的评论。
          【解决方案14】:

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

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

          【讨论】:

            【解决方案15】:

            这是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)
            

            【讨论】:

              【解决方案16】:

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

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

              【讨论】:

                【解决方案17】:

                我工作的应用程序需要通过 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;
                        }
                    }
                }
                

                【讨论】:

                  【解决方案18】:

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

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

                  【讨论】:

                    【解决方案19】:

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

                    /* somewhere else, for example in viewDidLoad() */
                    _wkWeb.scrollView.delegate = self;
                    
                    ..
                    
                    - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
                        scrollView.pinchGestureRecognizer.enabled = NO;
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      这对我有用。 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)
                      

                      【讨论】:

                        【解决方案21】:

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

                        webView.isUserInteractionEnabled = false

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

                        【讨论】:

                        • 这也将禁用滚动。仅仅因为内容是只读的,并不意味着您不能滚动浏览它。
                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多