WKWebView: evita el desplazamiento automático activado por la selección de texto del usuario

8

Cuando un usuario realiza un gesto de tocar y mantener presionado para seleccionar una palabra y luego arrastra el dedo hacia los bordes superior o inferior de la pantalla, la página se desplaza automáticamente para acomodar la selección.

aquí hay un breve clip que lo demuestra

Me gustaría evitar este comportamiento dentro de a WKWebView.

Esto es lo que he intentado hasta ahora:

en un bridge.jsarchivo accesible para la vista web:

var shouldAllowScrolling = true;

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

y luego en una WKScriptMessageHandlerimplementación:

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

Del mismo modo, he intentado llamar a la preventDefault()función directamente en el archivo javascript para varios eventos, a saber , scrolly touchmoveasí:

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

ambos métodos evitan con éxito el desplazamiento cuando se selecciona algún texto, pero no anulan el comportamiento descrito en la parte superior de mi pregunta.

Puedo aceptar soluciones en Swift y JavaScript o una combinación de ambos.

banana1
fuente

Respuestas:

5

Terminé resolviendo este problema guardando la última posición de desplazamiento y desplazándome a ella cuando era apropiado, así:

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

Si alguien puede ofrecer una solución más elegante que impida el desplazamiento por completo, no dude en aceptarla.

EDITAR:

Esta solución puede causar temblores / temblores de luz.

eso se puede resolver realizando el desplazamiento de forma nativa WKWebViewen lugar de llamar window.scrollTo()al javascript.

banana1
fuente