I've been experimenting with UITextField
and how to work with it's cursor position. I've found a number of relation Objective-C answers, as in
But since I am working with Swift, I wanted to learn how to get the current cursor location and also set it in Swift.
The answer below is the the result of my experimentation and translation from Objective-C.
This answer has been updated for Swift 3
The following content applies to both UITextField
and UITextView
.
Useful information
The very beginning of the text field text:
let startPosition: UITextPosition = textField.beginningOfDocument
The very end of the text field text:
let endPosition: UITextPosition = textField.endOfDocument
The currently selected range:
let selectedRange: UITextRange? = textField.selectedTextRange
Get cursor position
if let selectedRange = textField.selectedTextRange { let cursorPosition = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start) print("\(cursorPosition)") }
Set cursor position
In order to set the position, all of these methods are actually setting a range with the same start and end values.
To the beginning
let newPosition = textField.beginningOfDocument textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
To the end
let newPosition = textField.endOfDocument textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
To one position to the left of the current cursor position
// only if there is a currently selected range if let selectedRange = textField.selectedTextRange { // and only if the new position is valid if let newPosition = textField.position(from: selectedRange.start, offset: -1) { // set the new position textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition) } }
To an arbitrary position
Start at the beginning and move 5 characters to the right.
let arbitraryValue: Int = 5 if let newPosition = textField.position(from: textField.beginningOfDocument, offset: arbitraryValue) { textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition) }
Related
Select all text
textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)
Select a range of text
// Range: 3 to 7 let startPosition = textField.position(from: textField.beginningOfDocument, offset: 3) let endPosition = textField.position(from: textField.beginningOfDocument, offset: 7) if startPosition != nil && endPosition != nil { textField.selectedTextRange = textField.textRange(from: startPosition!, to: endPosition!) }
Insert text at the current cursor position
textField.insertText("Hello")
Notes
See also
in my case I had to use DispatchQueue:
func textViewDidBeginEditing(_ textView: UITextView) { DispatchQueue.main.async{ textField.selectedTextRange = ... } }
nothing else from this and other threads worked.
PS: I double checked which thread did textViewDidBeginEditing was running on, and it was main thread, as all UI should run on, so not sure why that little delay using main.asynch worked.