rebello95
rebello95

Reputation: 8576

Strange behavior when using setSelectedTextRange: on iOS 6

I'm seeing some very strange behavior with a UITextField. I have a custom keyboard implemented, and it works great on iOS 7+. However, on iOS 6, when the following line is called (after doing a "backspace"), the text field's cursor vanishes, it isn't editable without resigning and becoming the first responder again, and the placeholder and real text overlap.

Here's the relevant code for my "backspace" function:

//Get the position of the cursor
UITextPosition *selStartPos = self.textBeingEdited.selectedTextRange.start;
int start = (int)[self.textBeingEdited offsetFromPosition:self.textBeingEdited.beginningOfDocument toPosition:selStartPos];

//Make sure the cursor isn't at the front of the document
if (start > 0) {

    //Remove the character before the cursor
    self.textBeingEdited.text = [NSString stringWithFormat:@"%@%@", [self.textBeingEdited.text substringToIndex:start - 1], [self.textBeingEdited.text substringFromIndex:start]];

    //Move the cursor back 1 (by default it'll go to the end of the string for some reason)
    [self.textBeingEdited setSelectedTextRange:[self.textBeingEdited textRangeFromPosition:[self.textBeingEdited positionFromPosition:selStartPos offset:-1] toPosition:[self.textBeingEdited positionFromPosition:selStartPos offset:-1]]];
    //^This line is causing the issue
}

And here's what I'm seeing on iOS 6:

Strange behavior

Anyone have any insights on this? Thanks!

EDIT

This appears to be happening for every nonzero value being set as the offset.

Upvotes: 1

Views: 1018

Answers (1)

rebello95
rebello95

Reputation: 8576

EDIT: Completely new solution

Finally figured out the problem. Basically, from what I've seen, when you replace the text of a UITextField, it resets the selectedTextRange to the very end of the string (which makes sense since that's where the cursor is). With this in mind, I was able to come up with the following code which works on iOS 6 and 7.

//Get the position of the cursor
UITextPosition *startPosition = self.textBeingEdited.selectedTextRange.start;
int start = (int)[self.textBeingEdited offsetFromPosition:self.textBeingEdited.beginningOfDocument toPosition:startPosition];

//Make sure the cursor isn't at the front of the document
if (start > 0) {

    //Remove the character before the cursor
    self.textBeingEdited.text = [NSString stringWithFormat:@"%@%@", [self.textBeingEdited.text substringToIndex:(start - 1)], [self.textBeingEdited.text substringFromIndex:start]];
    //Note that this line ^ resets the selected range to just the very end of the string

    //Get the position from the start of the text to the character deleted's index - 1
    UITextPosition *position = [self.textBeingEdited positionFromPosition:self.textBeingEdited.beginningOfDocument offset:(start - 1)];

    //Create a new range with a length of 0
    UITextRange *newRange = [self.textBeingEdited textRangeFromPosition:position toPosition:position];

    //Update the cursor position (selected range with length 0)
    [self.textBeingEdited setSelectedTextRange:newRange];
}

Essentially what's happening is it's creating a UITextRange from a UITextPosition with length of 0 starting from the character before the character that was just deleted.

Hope this helps someone with a similar problem, I was going insane because of this!

Upvotes: 1

Related Questions