I am currently writing my first iOS application, Am I A Millionaire. One of the cool features I wanted to implement was to automatically format the currency that a user was entering, using the appropriate region formatting (e.g. commas to separate thousands in the US, and spaces if you were using South African Rand etc)
The code to format on the fly was pretty easy, but there was an issue of the cursor position being reset to the end of the string if you update a UITextField on the fly (e.g. field.text = @”some new value”). In order to get around this, I needed to find out where the cursor was before I changed the text, and then restore it afterwards.
As of iOS 5, this is a non-trivial process. At first it seemed simple – selectedTextRange returns a UITextRange object that has a start and end. Unfortunately, they are UITextPositions, not integers. This in a abstract class that you can’t get the members of to find out the index without violating Apple’s “don’t play with our privates” rule.
Fortunately, since UITextField conforms the UITextInput protocol. So, by comparing the current position to the end position, I was able to get the relative position of the cursor, and then restore it after setting the text. Sample code is below:
// Get the selected text range
UITextRange *selectedRange = [self selectedTextRange];
// Calculate the existing position, relative to the end of the field (will be a - number)
int pos = [self offsetFromPosition:self.endOfDocument toPosition:selectedRange.start];
// Change the text
self.text = lastValidated;
// Work out the position based by offsetting the end of the field to the same
// offset we had before editing
UITextPosition *newPos = [self positionFromPosition:self.endOfDocument offset:pos];
// Reselect the range, to move the cursor to that position
self.selectedTextRange = [self textRangeFromPosition:newPos toPosition:newPos];
Hacky, but it works. This seems to be a common theme with iOS development. I wish Windows Phone 7 had the same audience, as .net is so much better to work with
NB: I used the offset from the end, as it was easier to deal with backspace. If the iPhone supported delete, then this code wouldn’t work. Also, it doesn’t work so well when the user selects an actual range and hits backspace.
Comments
did you find some way working out under iOS4.0? Since UITextField doesn’t follow UITextInput protocol
Sorry, I was developing for iOS5+, so I am not sure
I remember stumbling across a couple of solutions for pre-iOS5 on stackoverflow. Perhaps this might help – http://stackoverflow.com/questions/618759/getting-cursor-position-in-a-uitextview-on-the-iphone
Thanks works fine on 5 and 6 iOS
Trackbacks
[...] could find the solution in objective c: Finding the cursor position in a UITextField It is however very unclear to me how to rewrite that in Monotouch. Any help with this would be [...]