UITextView selectAll method not working as expected
Asked Answered
F

3

12

I'm creating an iOS 8 app with Xcode 6.0.1 for my iPhone 5 (which has iOS 8.0.2 on it). I want to make it so that when a user clicks on my UITextView, all the text gets selected so he can easily start typing and erase what was there (but I don't want the text to be automatically erased because the user may want to keep it or append to it). To do this, I have the following code:

- (void)textViewDidBeginEditing:(UITextView *)textView {
    if ([textView hasText]) {
        NSLog(@"selectedRange before: %d", textView.selectedRange.length);
        [textView selectAll:self];
        NSLog(@"selectedRange after: %d", textView.selectedRange.length);
    }
}

When this method gets called, the console output is what I expect (i.e. the selectedRange length is the same as the number of characters in the textView's text). However, nothing shows up as selected in the UITextView and it doesn't act selected (i.e. no selection menu pops up).

I have seen multiple questions like this on the internet, but none of the provided solutions worked for me (and some of them wrote it off as a bug without providing any solution). Changing the sender id to something other than self (such as nil) did not help, and neither did it help to call [textView select:self] as one person suggested. I have also tried this code:

- (void)textViewDidBeginEditing:(UITextView *)textView {
    if ([textView hasText]) {
        UITextRange *range = [textView textRangeFromPosition:textView.beginningOfDocument toPosition:textView.endOfDocument];
        [textView setSelectedTextRange:range];
    }
}

But, it has the same problem.

Any suggestions?

Fillister answered 10/10, 2014 at 20:18 Comment(4)
Weird behaviour. As you can see in this video m.youtube.com/watch?v=iPXsVvva97E it should work like thisEvasive
Exactly. I saw that video too and can't figure out what I'm doing wrong.Fillister
i have the same issue, did you found any fix?Aq
Thanks for the reminder...I just posted the solution I'm currently using.Fillister
F
3

The best solution I've found for this issue so far is to create a custom UITextView (i.e. create a new class that extends UITextView) and then implement the selectAll method like this:

- (void)selectAll:(id)sender {
    [super selectAll:sender];
    UITextRange *selectionRange = [self textRangeFromPosition:self.beginningOfDocument toPosition:self.endOfDocument];
    [self performSelector:@selector(setSelectedTextRange:) withObject:selectionRange afterDelay:0.0];
}

Then when you use a text view, set its type to your custom text view type (in your code and in the storyboard). Now you can successfully call the selectAll method whenever you need to. I suppose this should work with UITextField too, but I haven't tried it yet.

Fillister answered 28/11, 2014 at 18:31 Comment(0)
A
33

This solution works too and does not require subclassing UITextView, just put this function on your delegate:

OBJECTIVE C -

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
  dispatch_async(dispatch_get_main_queue(), ^{
    [textView selectAll:nil];
  });
  return YES;
}

SWIFT 3 -

func textViewDidBeginEditing(_ textView: UITextView) {
    DispatchQueue.main.async {
        textView.selectAll(nil)
    }
}
Anisotropic answered 29/4, 2015 at 1:28 Comment(2)
This answer is totally ridiculous. It's also 100% right!Bedrock
Seriously...why does Apples docs not mention this? I'm sitting there not getting any errors calling selectAll and now a random push to the main.async queue fixes it??! what the what? Lol. sigh... apple fail... can anyone guess what's going on? maybe this "beginEditing" event is actually on the background async thread?Glochidiate
L
6

@brentvatne 's solution worked for me. Posting the Swift syntax so people can copy and paste in the future.

func textViewShouldBeginEditing(textView: UITextView) -> Bool {
    dispatch_async(dispatch_get_main_queue()) {
        textView.selectAll(nil)
    }
    return true
}
Librettist answered 13/11, 2015 at 1:21 Comment(0)
F
3

The best solution I've found for this issue so far is to create a custom UITextView (i.e. create a new class that extends UITextView) and then implement the selectAll method like this:

- (void)selectAll:(id)sender {
    [super selectAll:sender];
    UITextRange *selectionRange = [self textRangeFromPosition:self.beginningOfDocument toPosition:self.endOfDocument];
    [self performSelector:@selector(setSelectedTextRange:) withObject:selectionRange afterDelay:0.0];
}

Then when you use a text view, set its type to your custom text view type (in your code and in the storyboard). Now you can successfully call the selectAll method whenever you need to. I suppose this should work with UITextField too, but I haven't tried it yet.

Fillister answered 28/11, 2014 at 18:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.