如何给UITextView添加placeholder

引子

实际开发过程中,我们可能会使用到输入框,一般的需求我们都可以直接用UITextField来解决,我们都知道UITextFieldplaceholder属性,他可以提示用户正确的输入格式。但是,UITextField只支持单行输入,如果我们想做一个跟iMessage发送消息一样的输入框,或者新浪微博里面发微博的输入框,UITextField就无法满需求。

一个可行的解决办法是使用UITextView来做,因为UITextView支持换行。但是,UITextView没有placeholder这个属性,那么我们如何利用UITextView来做一个可行的可换行的输入框呢?

仔细研究了下iMessage里面的输入框,还有新浪微博里面发微博的输入框,发现这两个解决办法相同。跟网上流传的解决办法应该是一样的,也就是在UITextView上面加一个UILabel,用UILabeltext来充当placeholder,然后,监听UITextViewtext的变化,如果length为0,就显示这个UILabel,反之则隐藏。这种处理方法可以完全达到跟UITextFieldplaceholder一样的效果。

image

好了,方法已经告诉大家了,按照这个思路,大家都可以自己实现了。但是,本文将会介绍另一种方法,虽然这种方法比起在UITextView上面加UILabel的方法要稍微逊色一点(当UITextView成为firstResponder之后,我们实现的placeholder就会消失,可参见下面的最终效果图),但是基本的提示功能还是达到了,实现起来也是最好实现的。


实战演练

我们将通过自定义UITextView来实现一个支持placeholder的文本输入框。 首先,创建一个继承自UITextView的类ZCXTextView。 在.h文件中我们的代码如下:

1
2
3
@interface ZCXTextView : UITextView
@property (copy, nonatomic) NSString *placeholder;
@end

.m中重写了以及增加了以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (instancetype)init
{
self = [super init];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)awakeFromNib
{
[self setup];
}
- (void)setup
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidBeginEditingNotification:) name:UITextViewTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidEndEditingNotification:) name:UITextViewTextDidEndEditingNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

在setup方法中注册了两个Notification,分别来监听UITextView开始进入编辑和结束编辑这两个状态。两个方法实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)textViewDidBeginEditingNotification:(NSNotification *)notification
{
if ([super.text isEqualToString:_placeholder]) {
super.text = @"";
[super setTextColor:[UIColor blackColor]];
}
}
- (void)textViewDidEndEditingNotification:(NSNotification *)notification
{
if (super.text.length == 0) {
super.text = _placeholder;
[super setTextColor:[UIColor lightGrayColor]];
}
}

解释下上面代码的实现思路:

  • 在textViewDidBeginEditingNotification:这个方法中,当UITextView开始进入编辑状态的时候,如果UITextView的text为_placeholder,则不再显示_placeholder,将text设置为@””,并设置字体颜色为blackColor。
  • 在textViewDidEndEditingNotification:方法中当UITextView结束编辑的时候,如果UITextView的text长度为0,则设置其文字为_placeholder,并设置字体颜色为lightGrayColor。

然后,重写以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)setPlaceholder:(NSString *)placeholder
{
_placeholder = placeholder;
[self textViewDidEndEditingNotification:nil];
}
- (NSString *)text
{
NSString *text = [super text];
if ([text isEqualToString:_placeholder]) {
return @"";
}
return text;
}

这样我们在使用的时候就可以这样来用啦:

1
_textView.placeholder = @"分享新鲜事...";

最终实现效果如下:

image

项目代码已上传至github:在这里

另一种实现方式:利用Runtime实现,高度解耦:下载


小结

本文只是实现了一个简单的给UITextView添加placeholder的方法,这种方式虽然有点小瑕疵,但是基本的满足了需求。如果大家需要实现跟UITextField一样的placeholder的话,请参考这个


原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0