Disable automatic scrolling in WKWebView when a user selects text

When a user taps and holds to select a word, then moves their finger towards the top or bottom edges of the screen, the page automatically scrolls to adjust for the selection.

Watch a short clip demonstrating this

I am looking to disable this behavior within a WKWebView.

Here is what I have attempted so far:

In a bridge.js file that 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 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 using the preventDefault() function directly in the javascript file for events such as scroll and touchmove:

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

While both methods successfully prevent scrolling when text is selected, they do not override the initial behavior mentioned at the beginning of my question.

I am open to solutions involving Swift, JavaScript, or a combination of both.

Answer №1

After encountering the issue, I devised a solution by storing the previous scroll position and returning to it as needed. Here's how I implemented it:

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 stops touching the screen to allow scrolling while text selection is active
    shouldAllowScrolling = true;
});

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

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

If there is a more refined approach that completely prevents scrolling, I am open to accepting it.

EDIT:

Please note, this method may lead to slight shaking or jittering.

To address this, disable scrolling natively while shouldAllowScrolling is set to false, like so:

webView.scrollView.isScrollEnabled = false

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The .NET controller does not receive traffic for the GET method

Having some trouble populating a table with JSON data using angular ng-repeat. No errors are showing up in the console, and my breakpoint in the .NET Controller isn't being triggered. Here's the code for the App Controller: var app = angular.mo ...

Making cross-domain requests with jQuery (compatible with Python)

This Python script is running smoothly print 'foo' params = {'memberId': '1'} data = urllib.urlencode(params) url = 'http://aaa.bbb.com/ccc/' req = urllib2.Request(url, data, {'Content-Type': 'applica ...

Having trouble displaying the page due to ejs routing parameters and mongoose

Hey there, I have a user object that looks like this: { posts: [ { _id: 603f1c1b966c28291cb61d60, title: '1111', content: '1111', __v: 0 }, { _id: 603f5479c989d92fbc1d082c, title: ' ...

Resetting or removing the style attribute using JavaScript in Internet Explorer 9

I have a simple webpage spinner created using the Prototype JS framework: Within the nav frame: Event.observe( 'doit', 'click', function(){ parent.window.frames.cont.spinner.removeAttribute('style'); }, ...

Increasing the depth of JSON objects through multiple levels

Looking to expand upon an existing empty JSON object. After a couple of basic extensions, I end up with {size: 10, from: 0}. However, when attempting to use the $.extend function with multi-level JSON "query" : { "query_string" : ...

Utilizing JQuery click function to dynamically modify CSS styles

Snippet: <div id="r1242"> <img class="trans" src="http://sakshamcomputer.com/images/printerLogo.jpg"/> <div class="labels" id="p1242"> <strong>Available Printers:</strong><br><br> ...

What sets apart a React component from a function-as-component in React?

React is really confusing to me right now. Take this simple react component for example: export default function Foo(){ return( <div> <div>some text</div> </div> ) } I want to add a child compone ...

Ways to prevent Deno Workers from using cached source code

Good day, I am currently working on building a custom javascript code execution platform using Deno Workers. Additionally, I have implemented an Oak web server to manage requests for script modifications and their compilation and execution. An issue arise ...

How can I resolve the Angular 16 app error related to the missing 'results' property?

Lately, I've been immersed in developing a Single Page Application (SPA) using Angular 16, TypeScript, and The Movie Database (TMDB). Within app\services\movie-service.service.ts, my code snippet looks like this: import { Injectable } from ...

Employ SVG clusters as a sophisticated alternative to bars in D3 graphs

Imagine you have a complex data visualization created using D3. You want to go beyond just basic shapes like rectangles and instead build units with different graphics elements, such as rectangles, triangles, text labels, and background rectangles grouped ...

Arranging Checkboxes Vertically in HTML Without Using Inline Styling

My checkboxes are currently displayed in a column format, but I would like them to be in a single row. To better illustrate the issue, here is a photo: https://i.sstatic.net/PxRzB.jpg I am seeking assistance on how to align the checkboxes horizontally in ...

Gamepad interference causing obstruction of `requestAnimationFrame()`

I'm currently working with the Gamepad API and finding it a bit challenging due to its limited development. It appears that there is no "gamepadbuttondown" event available, which can be frustrating. I came across a library called 'awesome-react-g ...

The Vuetify data-table header array is having trouble accepting empty child associations

My Vuetify data-table relies on a localAuthority prop from a rails backend. Everything runs smoothly until an empty child association (nested attribute) is passed, specifically 'county': <script> import axios from "axios"; exp ...

Arranging a flex item below another flex item within a flexbox container

Is there a way to use flexbox to ensure that the 2.5 element is placed below the 2 element instead of beside it on the same row within the flex container? Given the HTML provided, how can I achieve this layout using flexbox? I attempted to accomplish thi ...

I'm curious why my padding is visible only when the element is being hovered over?

Recently delving into the world of html and css, I encountered a peculiar issue during coding. The padding of the list items only seems to appear in the hover state. In an attempt to rectify this, I crafted the following code snippet: * { margin: 0; ...

Guide to positioning buttons in the center of an image using Bootstrap 4

I need help centering buttons within two adjacent responsive images. The buttons are currently positioned below the images. Here is my code: <!--LAB1--> <div class="row"> <div class="col-lg-2 col-md-6 col-lg-6"> <div class="view overl ...

Loading data in a Bootstrap datatable can sometimes be a slow process

Hi there, I'm currently using a codeigniter bootstrap theme datatable to retrieve data from my database. However, the loading time is quite slow as it loads all the data at once before converting it into pagination. Is there any way to only load 10 re ...

Identify the credit card as either American Express or American Express Corporate

My JavaScript code can successfully detect credit card types, but I have encountered an issue. I am unable to differentiate between American Express and American Express Corporate cards. Is there a way to distinguish them or is it impossible to identify wh ...

There is an issue with the JSON format being received by fetch in JS when using json_encode in php

Recently, I encountered an issue with my JavaScript function that retrieves data from a PHP page. In the JS code block: fetch("print.php) .then(function (r) { return r.json() }) .then(function (values) { ...... ...... ...

Utilize the entire width for header elements

I have implemented four header elements: home, about, portfolio, and contact. I want these elements to stretch across the entire navigation bar with each taking up 25% of the space. How can I achieve this? Additionally, I specified that the home element sh ...