Last Updated: February 25, 2016
·
11.04K
· netbe

UITextField: changing the placeholder's color

If you google on how to change the placeholder color or font on an UITextField, you will certainly stumble upon this kind of code:

- (void)drawPlaceholderInRect:(CGRect)rect
{
    [[UIColor blueColor] setFill];
    [[self placeholder] drawInRect:rect withFont:[UIFont fontWithName:@"FlamaCondensed-Medium" size:[self.font pointSize]]];
}

So you just have to subclass UITextField and override this method.

This works fine until you need to change the color of the placeholder after the textfield has been drawn.

For example, on a form, I needed the placeholder color to change to red if the required field was empty, meaning redrawing the placeholder with a new color.

The problem was that calling setNeedsDisplay on the UITextField does not call the drawPlaceholderInRect method again.

Solution: Use attributedString

I ended up with with something like that:

- (void)setPlaceholder:(NSString *)placeholder
{
    self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholder attributes:@{
                                                        NSFontAttributeName: [UIFont fontWithName:@"FlamaCondensed-Medium" size:[self.font pointSize]],
                                             NSForegroundColorAttributeName:  [UIColor blueColor]}];
}

- (void)setNeedsDisplayError:(BOOL)hasError
{
    UIColor* color = hasError ? [UIColor redColor] : [UIColor blueColor];
    self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.attributedPlaceholder.string attributes:@{
                                                        NSFontAttributeName: [UIFont fontWithName:@"FlamaCondensed-Medium"
                                                                                             size:[self.font pointSize]],
                                             NSForegroundColorAttributeName: color}];
}

I am calling this public method setNeedsDisplayError whenever I have an error on the field.

NOTE: You could also just use the attributedPlaceholder directly without needing to subclass.

NOTE 2: attributedPlaceholder is available only since iOS 6.0