Uitextview: Disable Selection, Allow Links

UITextView: Disable selection, allow links

I find the concept of fiddling with the internal gesture recognizers a little scary, so tried to find another solution.
I've discovered that we can override point(inside:with:) to effectively allow a "tap-through" when the user isn't touching down on text with a link inside it:

// Inside a UITextView subclass:
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

guard let pos = closestPosition(to: point) else { return false }

guard let range = tokenizer.rangeEnclosingPosition(pos, with: .character, inDirection: .layout(.left)) else { return false }

let startIndex = offset(from: beginningOfDocument, to: range.start)

return attributedText.attribute(.link, at: startIndex, effectiveRange: nil) != nil
}

This also means that if you have a UITextView with a link inside a UITableViewCell, tableView(didSelectRowAt:) still gets called when tapping the non-linked portion of the text :)

UITextView avoid text selection, but keep tappable links

Add this UITextViewDelegate textViewDidChangeSelection and comment out isEditable and isSelectable:

func textViewDidChangeSelection(_ textView: UITextView) {
if textView.selectedTextRange != nil {
textView.delegate = nil
textView.selectedTextRange = nil
textView.delegate = self
}
}

UITextView link selectable without rest of text being selectable

This answer is for iOS 10.3.x and below where your UIView is not embedded in a subview. For a more robust, modern answer, please see Cœur's answer below.

You need to prevent the UITextView from becoming first responder.

1. Subclass UITextView to your own custom class (MyTextView).

2. Override canBecomeFirstResponder(). Here's an example in Swift:

Swift 3:

class MyTextView: UITextView {
override func becomeFirstResponder() -> Bool {
return false
}
}

Swift 2:

class MyTextView: UITextView {
override func canBecomeFirstResponder() -> Bool {
return false
}
}

Any links detected will still be enabled. I tested this with a phone number.

UITextView with clickable links but no text highlighting

I am working on the exact same problem and the best I could do was to instantly clear the selection as soon as it is made by adding the following to the UITextView's delegate:

- (void)textViewDidChangeSelection:(UITextView *)textView {
if(!NSEqualRanges(textView.selectedRange, NSMakeRange(0, 0))) {
textView.selectedRange = NSMakeRange(0, 0);
}
}

Note the check to prevent recursion. This pretty much addresses the issue because only selection is disabled -- links will still work.

Another tangential issue is that the text view will still become first responder, which you can fix by setting your desired first responder after setting the selected range.

Note: the only visual oddity that remains is that press-and-hold brings up the magnifying glass.

UITextView disabling text selection

Issue How disable Copy, Cut, Select, Select All in UITextView has a workable solution to this that I've just implemented and verified:

Subclass UITextView and overwrite canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
return NO;
}

Note that this disables links and other tappable text content.

Disable text selection in UITextView

Here comes Swift working example

class TextView: UITextView {

override func canPerformAction(action: Selector, withSender sender: AnyObject!) -> Bool {
return false
}

override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer!) -> Bool {
if gestureRecognizer.isKindOfClass(UITapGestureRecognizer) && ((gestureRecognizer as UITapGestureRecognizer).numberOfTapsRequired == 1) {
let touchPoint = gestureRecognizer.locationOfTouch(0, inView: self)
let cursorPosition = closestPositionToPoint(touchPoint)
selectedTextRange = textRangeFromPosition(cursorPosition, toPosition: cursorPosition)
return true
}
else {
return false
}
}

}


Related Topics



Leave a reply



Submit