Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Control cursor position in UITextField

I have a UITextField that I'm forcing formatting on by modifying the text inside the change notification handler. This works great (once I solved the reentrancy issues) but leaves me with one more nagging problem. If the user moves the cursor someplace other than the end of the string then my formatting change moves it to the end of the string. This means users cannot insert more than one character at a time into the middle of the text field. Is there a way to remember and then reset the cursor position in the UITextField?

like image 280
Jeremy Avatar asked Sep 30 '09 19:09

Jeremy


4 Answers

Controlling cursor position in a UITextField is complicated because so many abstractions are involved with input boxes and calculating positions. However, it's certainly possible. You can use the member function setSelectedTextRange:

[input setSelectedTextRange:[input textRangeFromPosition:start toPosition:end]];

Here's a function which takes a range and selects the texts in that range. If you just want to place the cursor at a certain index, just use a range with length 0:

+ (void)selectTextForInput:(UITextField *)input atRange:(NSRange)range {
    UITextPosition *start = [input positionFromPosition:[input beginningOfDocument] 
                                                 offset:range.location];
    UITextPosition *end = [input positionFromPosition:start
                                               offset:range.length];
    [input setSelectedTextRange:[input textRangeFromPosition:start toPosition:end]];
}

For example, to place the cursor at idx in the UITextField input:

    [Helpers selectTextForInput:input 
                        atRange:NSMakeRange(idx, 0)];
like image 116
Chris R Avatar answered Nov 19 '22 11:11

Chris R


Useful to position at index (Swift 3)

private func setCursorPosition(input: UITextField, position: Int) {
    let position = input.position(from: input.beginningOfDocument, offset: position)!
    input.selectedTextRange = input.textRange(from: position, to: position)
}
like image 44
George Muntean Avatar answered Nov 19 '22 10:11

George Muntean


I've finally found a solution for this problem! You can put the text you need inserted into the system pasteboard and then paste it at the current cursor position:

[myTextField paste:self]  

I found the solution on this person's blog:
http://dev.ragfield.com/2009/09/insert-text-at-current-cursor-location.html

The paste functionality is OS V3.0 specific, but I've tested it and it works fine for me with a custom keyboard.

If you go for this solution then you should probably save the user's existing clipboard contents and restore them immediately afterwards.

like image 3
Dan J Avatar answered Nov 19 '22 11:11

Dan J


Here's the Swift version of @Chris R. – updated for Swift3

private func selectTextForInput(input: UITextField, range: NSRange) {
    let start: UITextPosition = input.position(from: input.beginningOfDocument, offset: range.location)!
    let end: UITextPosition = input.position(from: start, offset: range.length)!
    input.selectedTextRange = input.textRange(from: start, to: end)
}
like image 2
gabuchan Avatar answered Nov 19 '22 10:11

gabuchan