在包含表情符号的UITextView中检测光标位置会在Swift 4中返回错误的位置

时间:2018-10-18 07:33:27

标签: swift xcode uitextfield uitextview

我正在使用此代码来检测光标在UITextView中的位置:

if let selectedRange = textView.selectedTextRange {

    let cursorPosition = textView.offset(from: textView.beginningOfDocument, to: selectedRange.start)

    print("\(cursorPosition)")
}

我将其放在textViewDidChange函数下,以在每次文本更改时检测光标位置。 它工作正常,但是当我放置表情符号时, textView.text.count 光标位置不同。从迅速4开始,每个表情符号都算作一个字符,但对于光标位置来说似乎是不同的。

enter image description here

enter image description here

那么如何获得与文本中字符数匹配的确切光标位置?

1 个答案:

答案 0 :(得分:2)

长话短说:将Swift与StringNSRange结合使用时,请将此扩展名用于范围转换

extension String {
    /// Fixes the problem with `NSRange` to `Range` conversion
    var range: NSRange {
        let fromIndex = unicodeScalars.index(unicodeScalars.startIndex, offsetBy: 0)
        let toIndex = unicodeScalars.index(fromIndex, offsetBy: count)
        return NSRange(fromIndex..<toIndex, in: self)
    }
}

让我们更深入地了解一下:

let myStr = "Wéll helló ⚙️"
myStr.count // 12
myStr.unicodeScalars.count // 13
myStr.utf8.count // 19
myStr.utf16.count // 13

Swift 4 字符串中是字符的集合(如ö这样的复合字符,表情符号将被视为一个字符)。 UTF-8 UTF-16 视图分别是UTF-8和UTF-16代码单元的集合。

您的问题是, textView.text.count 计算集合元素(表情符号和复合字符将作为一个元素),而NSRange计算UTF-16代码单元的索引。上面的片段说明了差异。


更多信息: Strings And Characters