Nice programing

WKWebView에서 확대 동작 비활성화

nicepro 2020. 12. 31. 23:26
반응형

WKWebView에서 확대 동작 비활성화


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에 선택적으로 전달, 핀치 제스처를 캡처하기 위해 자식보기 추가 등)을 알고 있지만 항상 이벤트에 지연이 발생하고 구현을 유지하고 싶습니다. 가능한 한 정리 / 해킹하지 마십시오.


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

아래 답변은 더 이상 iOS 10 베타에서 작동하지 않습니다.

Safari의 웹 사이트에 대한 접근성을 개선하기 위해 이제 사용자는 웹 사이트가 뷰포트에서 user-scalable = no를 설정하더라도 핀치 투 줌을 할 수 있습니다.


WKWebView는 예상대로 Mobile Safari와 같은 방식으로 뷰포트 메타 태그를 존중하는 것 같습니다. 그래서 페이지로드가 트릭을 수행 한 후 자바 스크립트를 통해 해당 태그를 DOM에 삽입하는 것을 발견했습니다. 웹뷰에 HTML이로드되는 것을 정확히 알지 못한다면이 솔루션이 지겨울 것입니다. 그렇지 않으면 의도하지 않은 결과를 초래할 것입니다. 제 경우에는 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, maximum-scale=1.0, user-scalable=no');document.getElementsByTagName('head')[0].appendChild(meta);";

    [webView evaluateJavaScript:javascript completionHandler:nil];
}

새 페이지에서만이 자바 스크립트를 실행해야하므로 방금 완료된 탐색의 종류를 살펴 보는 것이 좋습니다.


내가 설정 시도 minimumZoomScalemaximumZoomScale의 속성 UIScrollView1또는 isMultipleTouchEnabled재산 UIViewfalse또는 반환 nil호출에서 viewForZooming(in:)의를 UIScrollViewDelegate하지만 아무도 일하지. 제 경우에는 여러 번의 시행 착오 끝에 다음이 제 경우에 작동합니다 [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
   }
}

네이티브 솔루션이 저에게 효과가 없었고 JS를 주입하는 것은 이상적이지 않습니다. 확대 / 축소가 발생하고 델리게이트가 호출되면 webview를 초기화 할 때 비활성화 했음에도 불구하고 pinchGestureRecognizer가 활성화됩니다. 이 문제를 해결하기 위해 확대 / 축소가 시작될 때마다 비활성화하도록 설정했습니다.

extension ViewController: UIScrollViewDelegate {

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

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

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

이를 위해 UIScrollViewDelegate를 사용할 수 있습니다. 먼저 viewDidLoad () 또는 다른 적절한 메서드에서 webview에 대리자를 할당합니다.

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

로컬 html을 표시하는 경우이 html을 수정하고이 메타 태그를 html에 넣을 수 있습니다.

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

스위프트 2.0

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

이것이 one-webview-only 앱의 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;
    }    

}

답변에 댓글을 추가 할만한 평판이 충분하지 않지만 Kevin의 솔루션 (메타 뷰포트)이 더 이상 iOS 10 베타에서 작동하지 않는다는 점을 언급하고 싶었습니다. 그래도 Landschaft의 솔루션이 저에게 효과적입니다!

JS 솔루션은 W3C 표준을 사용하므로 항상 지원되어야합니다.

아, 케빈, 그렇게 됐으면 좋겠어요.

더보기 : https://stackoverflow.com/a/37859168/1389714


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


Disable double tap to zoom gesture by require failure of gesture recognizer. It will prevent the browser to take action when user double tap.

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


A simple way to prevent zooming

override func viewDidLoad() {
    super.viewDidLoad()

    webView.scrollView.delegate = self
}

func scrollViewDidZoom(_ scrollView: UIScrollView) {

    scrollView.setZoomScale(1.0, animated: false)
}

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

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


If the webview is user for read-only purposes, i.e, just for displaying the web content use

webView.isUserInteractionEnabled = false

By this the zoom gesture won't work on it.


Here's a slightly modified version of Gulshan Kumar's answer that worked for me in iOS 12.1.2, and it also prevents zooming due to double-taps and rotation. In my example, I just inject the script directly into the web view. I adjusted the scale to 60%, and there's no need to use concatenation in building up the source string.

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)

If it is better to disbaled the Pinch zoom when the webpage finish loading, and it can also specify which particular URL is going to be disbaled

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

    print("finish")
} 

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

This worked for me. 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)

ReferenceURL : https://stackoverflow.com/questions/25553711/disable-magnification-gesture-in-wkwebview

반응형