Question

I have a UIButton that controls the textColor of a UITextField, and I have found that when I call resignFirstResponder on the UITextField, any changes to the textColor made while the text field was first responder are lost, and the color is reverted to the state before becomeFirstResponder. The behavior I am looking for is that the textColor should remain as whatever is chosen while the text field is first responder.

Here is the relevant code:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tf = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 120.0f, self.view.bounds.size.width, 70.0f)];
    self.tf.delegate = self;
    self.tf.text = @"black";
    self.tf.font = [UIFont fontWithName:@"AvenirNext-DemiBold" size:48.0f];
    self.tf.textColor = [UIColor blackColor];
    [self.view addSubview:self.tf];
    self.tf.textAlignment = UITextAlignmentCenter;

    UIButton *b = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 220.0f, self.view.bounds.size.width, 20.0f)];
    [b addTarget:self action:@selector(changeColor:) forControlEvents:UIControlEventTouchUpInside];
    [b setTitle:@"Change color" forState:UIControlStateNormal];
    [b setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
    [self.view addSubview:b];
}

- (void)changeColor:(UIButton *)button {
    if ([self.tf.textColor isEqual:[UIColor blackColor]]) {
        self.tf.text = @"red";
        self.tf.textColor = [UIColor redColor];
    } else {
        self.tf.text = @"black";
        self.tf.textColor = [UIColor blackColor];
    }
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}

More specifically, the behavior is produced by the following actions:

  1. UITextField *tf initially black.
  2. Tap tf to becomeFirstResponder.
  3. Tap UIButton *b, tf.textColor changes to red (text also changes to @"red", although this is not necessary).
  4. Tap keyboard Return to resignFirstResponder, tf.textColor reverts back to black (text stays as @"red").

Analogously, if the initial textColor is red, the textField reverts back to red.

I've created an example project with only the features necessary to produce this behavior (available here). Thanks in advance.

Was it helpful?

Solution

As a workaround, you can just store the selected color on a property when the button is pressed and do this:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    textField.textColor = self.selectedColor;
    return YES;
}

UPDATE

As noted in the comments, a better place to put this workaround seems to be in textFieldDidEndEditing because it handles the case of jumping between fields:

- (void)textFieldDidEndEditing:(UITextField *)textField {
    textField.textColor = self.selectedColor;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top