Placeholder in UITextView

Here's an implementation of an override for UITextView that includes a placeholder.

It's pretty straight forward. We add an NSNotificaitonCenter observer for the UITextViewTextDidChangeNotification event. This event will be trigger when the text changes for our UITextView. We then add some logic to show or hide the placeholder text as appropriate.

The only tricky part is actually rendering the placeholder view. Which truthfully isn't that tricky. From a few other examples I've seen, I just tied it into the drawRect:rect method.

#import <UIKit/UIKit.h>

@interface PlaceholderTextView : UITextView

@property (strong, nonatomic) NSString *placeholder;

@end
#import "PlaceholderTextView.h"

@interface PlaceholderTextView()

@property (strong, nonatomic) UILabel *placeholderLabel;

@end

@implementation PlaceholderTextView

- (id) init {
    self = [super init];
    if(self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
    }
    return self;
}


- (void)textChanged:(NSNotification *)notification
{
    if(self.placeholder.length == 0)
        return;

    [UIView animateWithDuration:0.1 animations:^{
        [self showOrHidePlaceholder];
    }];
}

- (void)showOrHidePlaceholder
{
    if(self.text.length == 0)
        [self.placeholderLabel setAlpha:1.0];
    else
        [self.placeholderLabel setAlpha:0];
}

- (void)drawRect:(CGRect)rect
{
    if(self.placeholder.length > 0) {
        if(self.placeholderLabel == nil) {

            float linePadding = self.textContainer.lineFragmentPadding;
            CGRect placeholderRect = CGRectMake(self.textContainerInset.left + linePadding,
                                                self.textContainerInset.top,
                                                rect.size.width - self.textContainerInset.left - self.textContainerInset.right - 2 * linePadding,
                                                rect.size.height - self.textContainerInset.top - self.textContainerInset.bottom);
            self.placeholderLabel = [[UILabel alloc]initWithFrame:placeholderRect];
            self.placeholderLabel.font = self.font;
            self.placeholderLabel.textAlignment = self.textAlignment;
            self.placeholderLabel.textColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.3];
            [self addSubview:self.placeholderLabel];

            self.placeholderLabel.text = self.placeholder;
            [self.placeholderLabel sizeToFit];

        }
        [self showOrHidePlaceholder];
    }

    [super drawRect:rect];
}

- (void)setText:(NSString *)text
{
    [super setText:text];
    [self showOrHidePlaceholder];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
comments powered by Disqus