How to convert character index from layoutManager to String scale in swift? this is the code I'm using:
let touchPoint: CGPoint = gesture.locationOfTouch(0, inView: self.definitionLabel)
let index = layoutManager.characterIndexForPoint(touchPoint, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
please don't tell me to use advanceBy()
function on the first index of the string characterset since characters like ò count two in the scale of layoutManager but swift string counts theme once.
The index returned from the NSLayoutManager
is " NSString
based", ie it is the number of UTF-16 code units from the start of the string to the character at the given point. (So ò
actually counts as one, but Emojis 😀
count two and flags 🇧🇪
even count four.)
To convert that index to a valid Swift String
index, you can use the same approach as in https://stackoverflow.com/a/30404532/1187415 :
let text = ... // the stored text
let i16 = text.utf16.startIndex.advancedBy(index, limit: text.utf16.endIndex)
// i16 is a String.UTF16View.Index
if let strIndex = String.Index(i16, within: text) {
// strIndex is a String.CharacterView.Index
let char = text[strIndex]
print(char)
}
Updated for Swift 5
Martin R's answer gave me the rough outline; here's working Swift 5 version. Mine is for a UITextView with Attributed Text but should work just as well with regular String and for UITextField and UILabel.
func handleTap(_ sender: UIGestureRecognizer) {
guard let textView = sender.view as? UITextView else { return }
guard let plaintext = textView.attributedText?.string else { return }
//guard let plaintext = textView.text else { return }
let location = sender.location(in: textView)
let charIndex = textView.layoutManager.characterIndex(for: location, in: textView.textContainer,
fractionOfDistanceBetweenInsertionPoints: nil)
if let strIndex = plaintext.utf16.index(plaintext.utf16.startIndex, offsetBy: charIndex, limitedBy: plaintext.utf16.endIndex) {
let char = plaintext[strIndex]
print("Character tapped was \(char)")
}
}
let textTap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
textView.addGestureRecognizer(textTap)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.