WKWebView-防止用户文本选择触发自动滚动 [英] WKWebView - prevent automatic scrolling triggered by user text selection
问题描述
当用户执行点击并按住手势以选择一个单词,然后将手指向屏幕的顶部或底部拖动时,页面会自动滚动以适应选择。
我想在 WKWebView
中防止这种行为。
这是我尝试过的到目前为止:
在 bridge.js
文件中,该文件可通过网络视图访问:
var shouldAllowScrolling = true;
document.addEventListener('selectionchange',e => {
shouldAllowScrolling = getSelectedText()。length === 0;
window.webkit.messageHandlers.selectionChangeHandler.postMessage (
{
shouldAllowScrolling:shouldAllowScrolling
});
console.log('allow scrolling =',shouldAllowScrolling);
});
,然后在 WKScriptMessageHandler
实现中:
公共功能userContentController(_ userContentController:WKUserContentController,didReceive message:WKScriptMessage)
{
切换message.name
{
case selectionChangeHandler:
let params = paramsDictionary(fromMessageBody:message.body)
let shouldEnableScrolling = params [ shouldAllowScrolling]为?布尔?? true
cell?.webView.scrollView.isScrollEnabled = shouldEnableScrolling
cell?.webView.scrollView.isUserInteractionEnabled = shouldEnableScrolling //不与
以上的行一起使用默认值:
fatalError( \(#function):收到未定义的消息处理程序名称:\(message.name))
}
}
类似地,我尝试直接在JavaScript文件中调用 preventDefault()
函数来处理一系列事件,即滚动
和 touchmove
,如下所示:
document.addEventListener('touchmove',e => {
if(!shouldAllowScrolling){
e.preventDefault()
}
},{被动:假});
这两种方法都可以成功防止在选择某些文本时滚动,但不会覆盖最前面描述的行为我的问题。
我可以接受Swift和JavaScript或两者结合的解决方案。
我最终通过保存最后一个滚动位置并在适当的时候滚动到它来解决了这个问题,就像这样:
var shouldAllowScrolling = true;
var lastSavedScrollLeft = 0;
var lastSavedScrollTop = 0;
函数saveScrollPosition(){
lastSavedScrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
lastSavedScrollTop = window.pageYOffset || document.documentElement.scrollTop;
}
document.addEventListener('touchstart',e => {
saveScrollPosition();
});
document.addEventListener('touchend',()=> {
//在用户抬起手指时启用滚动,以允许在文本选择仍然存在时进行滚动
shouldAllowScrolling = true;
});
document.addEventListener('scroll',e => {
if(!shouldAllowScrolling){
window.scrollTo(lastSavedScrollLeft,lastSavedScrollTop);
}
});
document.addEventListener('selectionchange',e => {
shouldAllowScrolling = getSelectedText()。length === 0;
});
如果有人可以提供更优雅的解决方案来防止滚动,则完全不乐意接受它。 / p>
编辑:
此解决方案可能会引起轻微的抖动/抖动。
可以通过在 WKWebView
中执行滚动来解决,而不是调用 window.scrollTo ()
。
When a user performs a tap and hold gesture to select a word and then drags their finger towards either the top or bottom edges of the screen, the page automatically scrolls in order to accommodate the selection.
here is a short clip demonstrating it
I would like to prevent this behavior inside a WKWebView
.
Here is what I have tried so far:
in a bridge.js
file which is accessible to the webview:
var shouldAllowScrolling = true;
document.addEventListener('selectionchange', e => {
shouldAllowScrolling = getSelectedText().length === 0;
window.webkit.messageHandlers.selectionChangeHandler.postMessage(
{
shouldAllowScrolling: shouldAllowScrolling
});
console.log('allow scrolling = ', shouldAllowScrolling);
});
and then in a WKScriptMessageHandler
implementation:
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)")
}
}
Similarly, I have tried calling the preventDefault()
function directly in the javascript file for a bunch of events, namely scroll
and touchmove
, like so:
document.addEventListener('touchmove', e => {
if (!shouldAllowScrolling) {
e.preventDefault()
}
}, {passive: false});
both methods successfully prevent scrolling when some text is selected but do not override the behavior described at the very top of my question.
I can accept solutions in either Swift and JavaScript or a mix of both.
I ended up solving this problem by saving the last scroll position and scrolling to it when appropriate, like so:
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;
});
If someone can offer a more elegant solution that prevents the scrolling entirely ill be happy to accept it.
EDIT:
this solution may cause light shaking/jittering.
that can be solved by performing the scroll natively through the WKWebView
as opposed to calling window.scrollTo()
in the javascript.
这篇关于WKWebView-防止用户文本选择触发自动滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!