Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting Cursor position in UITextView that contains emojis returns the wrong position in swift 4

I'm using this code for detecting the cursor's position in a UITextView :

if let selectedRange = textView.selectedTextRange {

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

    print("\(cursorPosition)")
}

I put this under textViewDidChange func for detecting cursor position each time the text change. It is working fine but when I putting emojis the textView.text.count is different with the cursor position. from swift 4 each emoji counted as one character but it seems that for cursor position it is different.

enter image description here

enter image description here

so How can I get the exact cursor position that matches the count of characters in a text ?

like image 903
Sajjad Sarkoobi Avatar asked Oct 18 '18 07:10

Sajjad Sarkoobi


1 Answers

Long story short: When using Swift with String and NSRange use this extension for Range conversion

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's take a deeper look:

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

In Swift 4 string is a collection of characters (composite character like ö and emoji will count as one character). UTF-8 and UTF-16 views are the collections of UTF-8 and UTF-16 code units respectively.

Your problem is, that textView.text.count counts collection elements (emoji as well as composite character will count as one element) and NSRange counts indexes of UTF-16 code units. The difference is illustrated in the snipped above.


More here: Strings And Characters

like image 189
fewlinesofcode Avatar answered Nov 11 '22 22:11

fewlinesofcode