Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save yesleon/ad74f31b9ee86012fce8d476db1d949a to your computer and use it in GitHub Desktop.
Save yesleon/ad74f31b9ee86012fce8d476db1d949a to your computer and use it in GitHub Desktop.
This enables UITextView to be editable when being data detectable. Just set isEditableWhenBeingDataDetectable to true.
//
// UITextView+isEditableWhenBeingDataDetectable.swift
//
// Created by Li-Heng Hsu on 15/05/2018.
// Copyright © 2018 narrativesaw. All rights reserved.
//
import UIKit
extension UITextView {
@objc private func didReceiveTap(_ sender: UITapGestureRecognizer) {
guard sender.view === self else { return }
let location = sender.location(in: self)
guard let position = closestPosition(to: location) else { return }
let styleDictionary = textStyling(at: position, in: .forward) ?? [:]
openURL: if let url = styleDictionary[NSAttributedStringKey.link.rawValue] as? URL {
let location = offset(from: beginningOfDocument, to: position)
if delegate?.textView?(self, shouldInteractWith: url, in: NSRange(location: location, length: 0), interaction: .invokeDefaultAction) == false {
break openURL
}
UIApplication.shared.open(url)
} else if let range = textRange(from: position, to: position) {
isEditable = true
becomeFirstResponder()
selectedTextRange = range
}
}
@IBInspectable
var isEditableWhenBeingDataDetectable: Bool {
get {
return gestureRecognizers?.contains { $0 is LHTextViewEditableWhenBeingDataDetactableEnabler } == true
}
set {
if newValue {
if !isEditableWhenBeingDataDetectable {
let enabler = LHTextViewEditableWhenBeingDataDetactableEnabler(target: self, action: #selector(didReceiveTap))
addGestureRecognizer(enabler)
}
} else {
if let enabler = gestureRecognizers?.first(where: { $0 is LHTextViewEditableWhenBeingDataDetactableEnabler }) {
removeGestureRecognizer(enabler)
}
}
}
}
}
private class LHTextViewEditableWhenBeingDataDetactableEnabler: UITapGestureRecognizer {
override init(target: Any?, action: Selector?) {
super.init(target: target, action: action)
delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(didEndEditing), name: .UITextViewTextDidEndEditing, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc private func didEndEditing(notification: Notification) {
guard (notification.object as AnyObject) === view else { return }
(view as? UITextView)?.isEditable = false
}
}
extension LHTextViewEditableWhenBeingDataDetactableEnabler: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let textView = gestureRecognizer.view as? UITextView else { return false }
return !textView.isEditable
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment