One-click detection in UIWebView, but still support for selecting text and links

I use JavaScript to detect taps on a page that I am showing in a UIWebView, for example:

<div id="wrapper"> <a href="http://apple.com">Apple</a> </div> <script> document.getElementById("wrapper").addEventListener('click', function() { document.location = 'internal://tap'; }, false); </script> 

I intercept links with my delegate in a web view and searched for "internal: // tap". When I get this, I cannot view the web view and respond to the answer. However, in doing so, I lose the ability to select text. Clicking on the link still works correctly.

In fact, simply adding an event listener for 'click' removes the ability to select text, even if the handler does not try to reposition the document.

Any idea what I'm doing wrong?

+6
source share
2 answers

Apparently, if you put a click listener on an element, you can no longer select the text inside that element in iOS. My solution was to detect taps using a combination of touchstart, touchmove, and touchhend events along with a timer to ignore multiple taps and check the current selection of the document to make sure that the selection event is not occurring.

Here is the JS code I used:

 SingleTapDetector = function(element, handler) { this.element = element; this.handler = handler; element.addEventListener('touchstart', this, false); }; SingleTapDetector.prototype.handleEvent = function(event) { switch (event.type) { case 'touchstart': this.onTouchStart(event); break; case 'touchmove': this.onTouchMove(event); break; case 'touchend': this.onTouchEnd(event); break; } }; SingleTapDetector.prototype.onTouchStart = function(event) { this.element.addEventListener('touchend', this, false); document.body.addEventListener('touchmove', this, false); this.startX = this.currentX = event.touches[0].clientX; this.startY = this.currentY = event.touches[0].clientY; this.startTime = new Date().getTime(); }; SingleTapDetector.prototype.onTouchMove = function(event) { this.currentX = event.touches[0].clientX; this.currentY = event.touches[0].clientY; }; SingleTapDetector.prototype.onTouchEnd = function(event) { var that = this; // Has there been one or more taps in this sequence already? if (this.tapTimer) { // Reset the timer to catch any additional taps in this sequence clearTimeout(this.tapTimer); this.tapTimer = setTimeout(function() { that.tapTimer = null; }, 300); } else { // Make sure the user didn't move too much if (Math.abs(this.currentX - this.startX) < 4 && Math.abs(this.currentY - this.startY) < 4) { // Make sure this isn't a long press if (new Date().getTime() - this.startTime <= 300) { // Make sure this tap wasn't part of a selection event if (window.getSelection() + '' == '') { // Make sure this tap is in fact a single tap this.tapTimer = setTimeout(function() { that.tapTimer = null; // This is a single tap that.handler(event); }, 300); } } } } }; new SingleTapDetector(document.body, function(event) { document.location = "internal://tap"; }); 
+5
source

There is no need to use Javascript for this, it overflows when the UIGestureRecognizerDelegate has adequate methods. All you have to do is make sure that when you select text, the recognizer is not activated.

 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { BOOL hasTap = ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]); BOOL hasLongTouch = ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]); if (hasTap && hasLongTouch) { // user is selecting text return NO; } return YES; } 

This is about text selection, and links should work fine (at least they are for me).

+3
source

Source: https://habr.com/ru/post/903721/


All Articles