Отключить прокрутку двойным нажатием на WKWebView

У меня есть пользовательская клавиатура с WKWebView во всю ширину и высоту. Я отключил прокрутку с помощью wkWebView!.scrollView.scrollEnabled = false, но у меня все еще есть странное поведение прокрутки при двойном нажатии на нижнюю часть WKWebView. Вот исходный код простой веб-страницы, которую я пытаюсь загрузить: http://is.gd/gt8h2q (очень просто, просто полноэкранный div с зеленым фоном и одной строкой текста). Ниже GIF в качестве пояснения. Вот как я создаю WKWebView:

class KeyboardViewController: UIInputViewController, WKScriptMessageHandler {
var wkWebView: WKWebView?

override func loadView() {
    super.loadView()

    let contentController = WKUserContentController()
    contentController.addScriptMessageHandler(self, name:"callbackTestOne")

    let config = WKWebViewConfiguration()
    config.userContentController = contentController

    self.wkWebView = WKWebView(frame:self.view.frame, configuration:config)
    self.view = self.wkWebView!
}

override func viewDidLoad() {
    super.viewDidLoad()

    (...)

    wkWebView!.scrollView.bounces = false
    wkWebView!.scrollView.scrollEnabled = false
    wkWebView!.scrollView.backgroundColor = UIColor(red:248, green:248, blue:248, alpha:1)
    wkWebView!.scrollView.opaque = true
    wkWebView!.scrollView.showsHorizontalScrollIndicator = false
    wkWebView!.scrollView.showsVerticalScrollIndicator = false
    wkWebView!.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal
}

(...)

Объяснение GIF


person Beny    schedule 13.10.2015    source источник
comment
Все еще нерешенная проблема ... Я нашел грязный способ исправить: на моей локальной загруженной странице я использую jQuery для автоматической прокрутки вверх, когда позиция прокрутки равна › 0. Код: $(window).scroll(function() { if ( $(window).scrollTop() > 0 ) { $(window).scrollTop(0); }; });   -  person Beny    schedule 14.10.2015
comment
Это настоящая проблема. То же самое происходит при добавлении WKWebView в приложение или расширение iMessage.   -  person quemeful    schedule 03.02.2017


Ответы (5)


У меня была аналогичная проблема, и я нашел решение. То есть удалить UITapGestureRecognizer, ответственный за неправильное поведение.

В WKWebView, или, точнее, в UIScrollView и его подвидах, содержащихся в WKWebView, добавлено множество распознавателей жестов. Таким образом, вы можете легко перебрать все эти распознаватели в представлениях и удалить тот, который вам нужен.

Если вы хотите удалить все распознаватели двойного касания одним пальцем из веб-представления, вам необходимо выполнить поиск внутри подвидов прокрутки. Вы можете сделать следующее:

// iterate over all subviews of the WKWebView's scrollView
for subview in _webView.scrollView.subviews {

    // iterate over recognizers of subview
    for recognizer in subview.gestureRecognizers ?? [] {

        // check the recognizer is  a UITapGestureRecognizer
        if recognizer.isKind(of: UITapGestureRecognizer.self) {

            // cast the UIGestureRecognizer as UITapGestureRecognizer
            let tapRecognizer = recognizer as! UITapGestureRecognizer

            // check if it is a 1-finger double-tap
            if tapRecognizer.numberOfTapsRequired == 2 && tapRecognizer.numberOfTouchesRequired == 1 {

                // remove the recognizer
                subview.removeGestureRecognizer(recognizer)
            }
        }
    }
}

Это должно решить вашу проблему.

person Yves Tscherry    schedule 21.03.2017
comment
Хорошее объяснение! Работа для моего случая - разрешать только одно касание. Спасибо! - person Desmond DAI; 11.09.2017
comment
Этот способ работает для первоначального рендеринга веб-представления. Но после того, как вы ущипнете, чтобы увеличить веб-страницу, жест двойного нажатия вернется. Я не нашел первопричину. - person HongchaoZhang; 05.06.2019
comment
его следует вызывать после навигации didFinish, иначе не работает - person Ashkan Ghodrat; 22.07.2020

Хакерское и грязное решение. Но, по крайней мере, это работает. Просто добавьте свой собственный UITapGestureRecognizer в представление, содержащее WKWebView, и делегируйте свой UIViewController этому распознавателю жестов. Я использовал этот код:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if ([[otherGestureRecognizer description] containsString:@"WKSyntheticClickTapGestureRecognizer"] && [[otherGestureRecognizer description] containsString:@"numberOfTapsRequired = 2"]) {
        [otherGestureRecognizer removeTarget:nil action:nil];
        return YES;
    }

Обновление 1 После некоторых исследований я обнаружил, что этот подход не так хорош. Потому что у нас есть проблемы с долгим нажатием в меню, особенно с отменой выделенного текста. И для меня все еще была проблема - сделайте долгое нажатие, когда появится меню, слегка проведите пальцем влево или вправо - иногда WKWebView мог начать прокрутку. Следующий подход заключается в настройке WKSelectionGranularityCharacter для WKWebViewConfiguration — это не очевидно, я должен сказать (Apple, зачем вы это делаете?). двойной тап, каждый жест работает как надо. Однако для iOS9 у нас плохие новости — http://www.openradar.me/23345435 она не работает. Так что продолжайте расследование.

person Alexander Slabinsky    schedule 20.01.2016

Это переработанная версия, написанная на Swift 4.2. Просто передайте свой WKWebView в качестве параметра и вызовите функцию где-нибудь вроде viewDidLoad.

private func deleteDoubleTap(web: WKWebView) {
    for subview in web.scrollView.subviews {            
        let recognizers = subview.gestureRecognizers?.filter{$0 is UITapGestureRecognizer}
        recognizers?.forEach{recognizer in
            let tapRecognizer = recognizer as! UITapGestureRecognizer
            if tapRecognizer.numberOfTapsRequired == 2 && tapRecognizer.numberOfTouchesRequired == 1 {
                subview.removeGestureRecognizer(recognizer)
            }
        }
    }

}
person Roman    schedule 16.08.2018

Та же идея, что и https://stackoverflow.com/a/42939172/2883860, но немного более современная.

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    webView.scrollView.subviews.forEach { subview in
        subview.gestureRecognizers?.forEach { recognizer in
            if let tapRecognizer = recognizer as? UITapGestureRecognizer,
                tapRecognizer.numberOfTapsRequired == 2 && tapRecognizer.numberOfTouchesRequired == 1 {
                subview.removeGestureRecognizer(recognizer)
            }
        }
    }
}
person pchelnikov    schedule 28.11.2019

Предполагая, что вы контролируете контент, отображаемый в этом WKWebView, вы должны установить для него правильный экран просмотра. Это, скорее всего, отключит это поведение.

Как насчет:

<meta id="viewport" name="viewport"
    content="width=device-width; user-scalable=false" />
person Stefan Arentz    schedule 18.10.2015
comment
Да, я пробовал с этим вьюпортом. Но все же эта проблема с прокруткой: с - person Beny; 19.10.2015