Think Big Act Local

iPhone開発を軸にブレブレの記事を書いていきます。

Placeholderを使えるUITextViewを作る

プレースホルダーとは、フォームに何も入力されてない時に表示される代替文字のこと。
下の画像でいう「ツイートする」に当たる部分で、1文字以上の入力で隠れます。
iOSではそのままプレースホルダー、AndroidではHintと呼ばれます。

f:id:himaratsu:20130430132329p:plain

UITextFieldにはplaceholderプロパティが存在するのですが、
なぜかUITextViewにはこの機能がなく、使うことが出来ません。

どうしようかと思っていたらStackOverFlowにドンピシャの回答があったので、
今回はそれを基にplaceholderつきのUITextViewを自作してみます。

PlaceHolderつきのUITextView

UIPlaceHolderTextView.h

#import <Foundation/Foundation.h>

@interface UIPlaceHolderTextView : UITextView

@property (nonatomic, retain) NSString *placeholder;
@property (nonatomic, retain) UIColor *placeholderColor;

-(void)textChanged:(NSNotification*)notification;

@end

UIPlaceHolderTextView.m

#import "UIPlaceHolderTextView.h"

@interface UIPlaceHolderTextView ()

@property (nonatomic, retain) UILabel *placeHolderLabel;

@end

@implementation UIPlaceHolderTextView

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
#if __has_feature(objc_arc)
#else
    [_placeHolderLabel release]; _placeHolderLabel = nil;
    [_placeholderColor release]; _placeholderColor = nil;
    [_placeholder release]; _placeholder = nil;
    [super dealloc];
#endif
}

- (void)awakeFromNib
{
    [super awakeFromNib];

    // Use Interface Builder User Defined Runtime Attributes to set
    // placeholder and placeholderColor in Interface Builder.
    if (!self.placeholder) {
        [self setPlaceholder:@""];
    }

    if (!self.placeholderColor) {
        [self setPlaceholderColor:[UIColor lightGrayColor]];
    }

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}

- (id)initWithFrame:(CGRect)frame
{
    if( (self = [super initWithFrame:frame]) )
    {
        [self setPlaceholder:@""];
        [self setPlaceholderColor:[UIColor lightGrayColor]];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
    }
    return self;
}

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

    if([[self text] length] == 0)
    {
        [[self viewWithTag:999] setAlpha:1];
    }
    else
    {
        [[self viewWithTag:999] setAlpha:0];
    }
}

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

- (void)drawRect:(CGRect)rect
{
    if( [[self placeholder] length] > 0 )
    {
        if (_placeHolderLabel == nil )
        {
            _placeHolderLabel = [[UILabel alloc]
                                       initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
            _placeHolderLabel.lineBreakMode = NSLineBreakByWordWrapping;
            _placeHolderLabel.numberOfLines = 0;
            _placeHolderLabel.font = self.font;
            _placeHolderLabel.backgroundColor = [UIColor clearColor];
            _placeHolderLabel.textColor = self.placeholderColor;
            _placeHolderLabel.alpha = 0;
            _placeHolderLabel.tag = 999;
            [self addSubview:_placeHolderLabel];
        }

        _placeHolderLabel.text = self.placeholder;
        [_placeHolderLabel sizeToFit];
        [self sendSubviewToBack:_placeHolderLabel];
    }

    if( [[self text] length] == 0 && [[self placeholder] length] > 0 )
    {
        [[self viewWithTag:999] setAlpha:1];
    }

    [super drawRect:rect];
}

@end

これでOKです。
UITextViewTextDidChangeNotificationイベントを監視し、発生した際には
textChangedメソッドでプレースホルダー文を出すかどうかを判断します。

UIPlaceHolderTextViewの使い方

UITextViewの拡張クラスなので、基本的にはUITextViewと同じです。
それに追加で以下のプロパティが使えます。

プロパティ 説明 デフォルト値
placeholder プレースホルダーの文章 なし(表示されない)
placeholderColor プレースホルダーの文字色 [UIColor lightGrayColor]

使用例

UIPlaceHolderTextView *textView = [[UIPlaceHolderTextView alloc]
                  initWithFrame:CGRectMake(0, 0, 300, 100)];
textView.placeholder         = @"テキストを入力してください";
textView.placeholderColor = [UIColor redColor];

今回は以上です。

参考リンク

ソースはこちらから拝借しました。
Placeholder in UITextView - StackOverFlow

広告を非表示にする