Created
May 31, 2023 08:35
-
-
Save anngdev/1bca0e26ea8d2823da20cdfc2e2a8bdb to your computer and use it in GitHub Desktop.
Detect UITextView character on touched (UITextView only)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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