Reputation: 83
The standard method I use to get the cursor position in a UITextfield does not seem to work with some emojis. The following code queries a textField for cursor position after insertion of two characters, first an emoji and then a letter character. When the emoji is inserted into the textField the function returns a value of 2 for the cursor position instead of the expected result of 1. Any ideas into what I am doing wrong or how to correct this. Thanks
Here is the code from an xcode playground:
class MyViewController : UIViewController {
override func loadView() {
//setup view
let view = UIView()
view.backgroundColor = .white
let textField = UITextField()
textField.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
textField.textColor = .black
view.addSubview(textField)
self.view = view
//check cursor position
var str = "🐊"
textField.insertText(str)
print("cursor position after '\(str)' insertion is \(getCursorPosition(textField))")
textField.text = ""
str = "A"
textField.insertText(str)
print("cursor position after '\(str)' insertion is \(getCursorPosition(textField))")
}
func getCursorPosition(_ textField: UITextField) -> Int {
if let selectedRange = textField.selectedTextRange {
let cursorPosition = textField.offset(from: textField.beginningOfDocument, to: selectedRange.end)
return cursorPosition
}
return -1
}
}
the code return the following output:
cursor position after '🐊' insertion is 2
cursor position after 'A' insertion is 1
I'm trying to use the cursor position to split the text string into two pieces -- the text that occurs before the cursor and the text that occurs after the cursor. To do this I use the cursor position as an index for a character array I have created using the map function as follows. The cursor position leads to an incorrect array index with an emoji
var textBeforeCursor = String()
var textAfterCursor = String()
let array = textField.text!.map { String($0) }
let cursorPosition = getCursorPosition(textField)
for index in 0..<cursorPosition {
textBeforeCursor += array[index]
}
Upvotes: 3
Views: 1689
Reputation: 318874
Your issue is that the NSRange
value returned by UITextField selectedTextRange
and the offset
need to be properly converted to a Swift String.Index
.
func getCursorPosition(_ textField: UITextField) -> String.Index? {
if let selectedRange = textField.selectedTextRange {
let cursorPosition = textField.offset(from: textField.beginningOfDocument, to: selectedRange.end)
let positionRange = NSRange(location: 0, length: cursorPosition)
let stringOffset = Range(positionRange, in: textField.text!)!
return stringOffset.upperBound
}
return nil
}
Once you have that String.Index
you can split the string.
if let index = getCursorPosition(textField) {
let textBeforeCursor = textField.text![..<index]
let textAfterCursor = textField.text![index...]
}
Upvotes: 4