如何在swift中将字符索引从layoutManager转换为String scale

时间:2016-06-13 02:50:00

标签: ios swift cocoa cocoa-touch

如何在swift中将字符索引从layoutManager转换为String scale? 这是我正在使用的代码:

let touchPoint: CGPoint = gesture.locationOfTouch(0, inView: self.definitionLabel)
let index = layoutManager.characterIndexForPoint(touchPoint, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

请不要告诉我在字符串字符集的第一个索引上使用advanceBy()函数,因为像ò这样的字符在layoutManager的规模中计数为2,但是swift字符串计数主题一次。

2 个答案:

答案 0 :(得分:2)

NSLayoutManager返回的索引是" NSString基于", 即它是字符串开头的UTF-16代码单元的数量 在给定点上的角色。 (所以ò实际上算作 一个,但Emojis 计数两个,标志计算四个。)

要将该索引转换为有效的Swift String索引,您可以使用 与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)
} 

答案 1 :(得分:0)

已为Swift 5更新

马丁·R的回答给了我粗略的轮廓;这是工作中的Swift 5版本。我的是用于带有属性文本的UITextView,但应该与常规String以及UITextField和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)