WKWebView - Verhindert das automatische Scrollen, das durch die Auswahl von Benutzertexten ausgelöst wird

8

Wenn ein Benutzer eine Geste zum Tippen und Halten ausführt, um ein Wort auszuwählen, und dann seinen Finger entweder zum oberen oder unteren Rand des Bildschirms zieht, wird die Seite automatisch gescrollt, um die Auswahl anzupassen.

Hier ist ein kurzer Clip, der dies demonstriert

Ich möchte dieses Verhalten in einem verhindern WKWebView.

Folgendes habe ich bisher versucht:

in einer bridge.jsDatei, auf die die Webansicht zugreifen kann:

var shouldAllowScrolling = true;

document.addEventListener('selectionchange', e => {
    shouldAllowScrolling = getSelectedText().length === 0;
    window.webkit.messageHandlers.selectionChangeHandler.postMessage(
        {
            shouldAllowScrolling: shouldAllowScrolling
        });
    console.log('allow scrolling = ', shouldAllowScrolling);
});

und dann in einer WKScriptMessageHandlerImplementierung:

public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
    {
        switch message.name
        {
        case "selectionChangeHandler":
            let params = paramsDictionary(fromMessageBody: message.body)
            let shouldEnableScrolling = params["shouldAllowScrolling"] as? Bool ?? true
            cell?.webView.scrollView.isScrollEnabled = shouldEnableScrolling
            cell?.webView.scrollView.isUserInteractionEnabled = shouldEnableScrolling // not together with the line above 
        default:
            fatalError("\(#function): received undefined message handler name: \(message.name)")
        }
    }

In ähnlicher Weise habe ich versucht, die preventDefault()Funktion direkt in der Javascript-Datei für eine Reihe von Ereignissen aufzurufen , nämlich scrollund touchmovewie folgt:

document.addEventListener('touchmove', e => {
    if (!shouldAllowScrolling) {
        e.preventDefault()
    }
}, {passive: false});

Beide Methoden verhindern erfolgreich das Scrollen, wenn Text ausgewählt ist, überschreiben jedoch nicht das oben ganz oben in meiner Frage beschriebene Verhalten.

Ich kann Lösungen entweder in Swift und JavaScript oder in einer Mischung aus beiden akzeptieren.

banana1
quelle

Antworten:

5

Am Ende habe ich dieses Problem gelöst, indem ich die letzte Bildlaufposition gespeichert und gegebenenfalls dorthin gescrollt habe, wie folgt:

var shouldAllowScrolling = true;
var lastSavedScrollLeft = 0;
var lastSavedScrollTop = 0;

function saveScrollPosition() {
    lastSavedScrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
    lastSavedScrollTop = window.pageYOffset || document.documentElement.scrollTop;
}

document.addEventListener('touchstart', e => {
    saveScrollPosition();
});

document.addEventListener('touchend', () => {
    // enable scrolling when the user lifts their finger, to allow scrolling while text selection is still present
    shouldAllowScrolling = true;
});

document.addEventListener('scroll', e => {
    if (!shouldAllowScrolling) {
        window.scrollTo(lastSavedScrollLeft, lastSavedScrollTop);
    }
});

document.addEventListener('selectionchange', e => {
    shouldAllowScrolling = getSelectedText().length === 0;
});

Wenn jemand eine elegantere Lösung anbieten kann, die verhindert, dass das Scrollen völlig krank wird, akzeptieren Sie sie gerne.

BEARBEITEN:

Diese Lösung kann leichtes Schütteln / Zittern verursachen.

Dies kann gelöst werden, indem der Bildlauf nativ durchgeführt wird WKWebView, anstatt window.scrollTo()das Javascript aufzurufen .

banana1
quelle