Skip to content

Instantly share code, notes, and snippets.

@anngdev
Created May 31, 2023 08:35
Show Gist options
  • Save anngdev/1bca0e26ea8d2823da20cdfc2e2a8bdb to your computer and use it in GitHub Desktop.
Save anngdev/1bca0e26ea8d2823da20cdfc2e2a8bdb to your computer and use it in GitHub Desktop.
Detect UITextView character on touched (UITextView only)
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var label: UITextView!
@IBOutlet weak var labelOverlat: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(labelTapped(_:)))
label.isUserInteractionEnabled = true
label.addGestureRecognizer(tapGesture)
}
@objc func labelTapped(_ gesture: UITapGestureRecognizer) {
guard let label = gesture.view as? UITextView else { return }
let attributedText = label.attributedText ?? NSAttributedString(string: label.text ?? "")
let text = attributedText.string
let font = label.font ?? UIFont.systemFont(ofSize: 17.0)
let textStorage = NSTextStorage(attributedString: attributedText)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: label.bounds.size)
layoutManager.addTextContainer(textContainer)
let location = gesture.location(in: label)
let textOffset = CGPoint(x: location.x, y: location.y)
let characterIndex = layoutManager.characterIndex(for: textOffset, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
if characterIndex < text.count {
let characterRange = NSRange(location: characterIndex, length: 1)
let glyphRange = layoutManager.glyphRange(forCharacterRange: characterRange, actualCharacterRange: nil)
var glyphRect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
glyphRect.origin.x += label.textContainerInset.left
glyphRect.origin.y += label.textContainerInset.top
let lineRect = layoutManager.lineFragmentUsedRect(forGlyphAt: glyphRange.location, effectiveRange: nil)
let finalRect = CGRect(x: glyphRect.origin.x, y: lineRect.origin.y, width: glyphRect.width, height: lineRect.height)
if finalRect.contains(location) {
let tappedCharacter = (label.text as NSString?)?.substring(with: NSRange(location: characterIndex, length: 1))
print("Tapped character: \(tappedCharacter)")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment