Getting and Setting Cursor Position of UITextField and UITextView in Swift
Solution 1
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
Use
textField.becomeFirstResponder()
to give focus to the text field and make the keyboard appear.See this answer for how to get the text at some range.
See also
Solution 2
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.
Solution 3
For set cursor position at your point:
textView.beginFloatingCursor(at: CGPoint(x: 10.0, y: 10.0))
For reset cursor position:
textView.endFloatingCursor()
Note: This example works in both Textview & Textfield.
Solution 4
let range = field.selectedTextRange
field.text = "hello world"
field.selectedTextRange = range
Solution 5
I hadn't even noticed that the textView in one of my published apps actually starts from the left after you delete a word on the top line of the textView. Not only was the caret going to the left but the text would then start from the left where the caret was when you typed something! It wouldn't do it in a middle line or the bottom line, only when the line was deleted on the top.
func textViewDidChange(_ textView: UITextView)
{
if myTextView.text!.count > 0
{
myTextView.textAlignment = .center
}
}
The caret still goes to the left which is not ideal but at least with that 'if' statement added, it will only add the text from the centre as intended and won't add the text from the left.
Comments
-
Suragch almost 3 years
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- Getting the cursor position of UITextField in ios
- Control cursor position in UITextField
- UITextField get currently edited word
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.
-
mfaani over 7 yearsWhat is the purpose of startPosition? What can you do with it? Also what is the purpose that one might need to get the cursor position?
-
Suragch over 7 years@Honey, I used that variable name to refer to two different things here. The first was to refer to the beginning of the text field. It would be useful if you wanted to move the cursor there. The second was to refer to the begging of a selected range of text. It is useful if you want to copy that range or set some attribute on it.
-
Yucel Bayram over 7 yearsIs there anything to move cursor to right while textfield is empty ? I followed your answer but i could not make it.
-
Suragch over 7 years@yucelbayram, If the text field is empty, then there is nowhere to move the cursor to. The cursor can only move through text. What are you trying to do?
-
Yucel Bayram over 7 yearsOh ok i figured it out. But you have an idea about that one ? For example its a text with 5 letters, you dont know what is this, but first letter is given. Just like a H_ _ _ _ , (it is "HELLO"). When user start to type, I want to cursor move to second index and skip the first one(H letter.). If this is out of topic, its fine. Thanks anyway.
-
Suragch over 7 years@yucelbayram, You can place the cursor after the H using
textField.endOfDocument
. You could also use underscores or spaces to represent the missing letters. -
Fattie about 7 years@Suragch thanks for another great canonical answer. An ultimate addition would be get pixel position of cursor in iOS10 (there are many messy, archaic, posts on this issue). And a "last-word" addition would be the converse, find cursor character position .. given a pixel position! :)
-
Suragch about 7 years@JoeBlow, yes, that would be a useful addition. This is something I will have to learn in the future, too, because I want to make a custom text view that will draw its own cursor.
-
Ryan Poolos almost 7 yearsIs it possible to set the selectedTextRange in an animated fashion so that if its placed at the bottom you get a typical smooth scroll like setting the contentOffset?
-
Suragch almost 7 years@RyanPoolos, I'm guessing it is possible, but I don't know how to do it. This would make a good new question. Link to it if you do.
-
Ryan Poolos almost 7 yearsI've got a janky work around but posted a question incase someone has something better. stackoverflow.com/q/45216232/563381
-
Michael Ozeryansky over 5 yearsIt's not a delay but the next run loop. Most likely the textfield's selected range is being modified by the same function that called
textViewDidBeginEditing
. So by placing it on the queue, it will happen after the caller has finished. -
Mamta over 5 years@Suragch please help me with this answer too : stackoverflow.com/a/53475629/2714877
-
Vyachaslav Gerchicov over 5 yearswhy is it accepted as the answer? According to it
cursor position == 0
andcursor position is undefined
are the same. -
Suragch over 5 years@VyachaslavGerchicov, Sorry, I don't understand your comment. Although
UITextPosition
is not exactly the same as an integer index, for plain text it works out to be the same as the offset from the beginning of the document. The cursor position at0
means it is at the start of the text. It is not undefined. A negative value would be undefined. -
Vyachaslav Gerchicov over 5 years@Suragch I want to create something like phone keypad screen from the native app. So when
cursor position == 0
backspace button does nothing but ifcursor position is undefined
backspace removes the last symbol. In your answer these cases are mixed because I always get zero value even when its position is undefined. The only solution I found is additional checking ofisFirstResponder
property but it is not even mentioned in your answer! -
amin over 5 yearswhy Set cursor position not work in 'textViewShouldBeginEditing' and 'textViewDidBeginEditing'
-
Parth Patel about 5 years@Suragch Floating Cursor is one method to set cursor location in textView or textField.
-
Sevy11 about 5 yearsAny idea how to track/set the cursor in a UISearchBar object?
-
Fattie almost 5 years@Suragch , I've got one for you. A thing is to change the keyboar style, as you enter. Example. Bank numbers are: "First two characters must be A-Z; the rest must be digits". Readers want to know how to reliably change the keybard style (in the example, between ascii and digits) and what to do so on (IMO, the cursor position).
-
Suragch almost 5 years@ArielSD, I'm sorry, I haven't worked on this for a while. I can't remember.
-
timetowonder over 4 years@MichaelOzeryansky Yeah, I think so, too. But this begs the question — what IS the right method to be setting cursor position manually?
-
T.Eswaran over 3 yearsHi All, I have one small doubt. How to get the click position when clicking a specific character after entering some characters in the UITextField.
-
Suragch over 3 years@T.Eswaran, This isn't quite what you're asking, but you can check this out:stackoverflow.com/a/32262426/3681880
-
Panks almost 2 yearsusing dispatch queue worked for me too, thanks