iOS开发中,UITextView是一个我们需要经常使用的组件,每次使用都需要默认占位文字,用于告诉用户需要输入什么内容,但是UITextView没有placeHolder这个属性,这篇文章主要介绍相应的解决办法
最终的效果图为:
Demo地址
1.使用UITextView的开始编辑和结束编辑的协议实现
项目中对应的实现文件为:FirstSolutionViewController
UITextViewDelegate中有两个协议方法
//开始编辑时调用
- (void)textViewDidBeginEditing:(UITextView *)textView;
//结束编辑时调用
- (void)textViewDidEndEditing:(UITextView *)textView;
这个方法就是通过这两个方法实现相应的效果
//UITextView懒加载
- (UITextView *)textView {
if (_textView) {
return _textView;
}
_textView = [[UITextView alloc] initWithFrame:CGRectZero];
_textView.font = [UIFont systemFontOfSize:18];
_textView.textColor = [UIColor whiteColor];
_textView.backgroundColor = [UIColor greenColor];
_textView.textContainerInset = UIEdgeInsetsMake(25, 10, 10, 10);
_textView.text = @"请输入相应的内容";
_textView.delegate = self;
//这个属性的作用是在键盘上添加一个完成按钮,点击完成按钮可以收起键盘
_textView.shouldShowHideKeyBoardBtn = YES;
return _textView;
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
//判断开始编辑时,文本的内容是不是和自己预设的相同,相同的话将其清空
if ([textView.text isEqualToString:@"请输入相应的内容"]) {
textView.text = @"";
}
}
- (void)textViewDidEndEditing:(UITextView *)textView {
//当结束编辑时,如果text长度小于1,那么显示原本的placeHolder文字(只有收起键盘才算编辑结束)
if (textView.text.length < 1) {
textView.text = @"请输入相应的内容";
}
}
最终效果图为:
最终效果图
这种方法的缺陷很大,一方面是在没有点击完成按钮,但是text已经被清空的情况下,占位文字不会出现,而且通用性也不是很好,每次使用UILabel都需要这么写(不推荐使用这种方法)
2.添加Label,用来展示placeHolder占位文字
我们可以在UITextView上添加一个UILabel,用label来展示占位文字,同时通过对输入的文本进行判断,来控制label的显示于隐藏,相应的实现文件是SecondSolutionViewController
定义相应的UITextView和UILabel
@property (nonatomic, strong) UITextView *textView;
@property (nonatomic, strong) UILabel *placeHolder;
相应的懒加载为:
- (UITextView *)textView {
if (_textView) {
return _textView;
}
_textView = [[UITextView alloc] initWithFrame:CGRectZero];
_textView.font = [UIFont systemFontOfSize:18];
_textView.textColor = [UIColor whiteColor];
_textView.backgroundColor = [UIColor greenColor];
_textView.textContainerInset = UIEdgeInsetsMake(25, 10, 10, 10);
//键盘上添加一个完成按钮
_textView.shouldShowHideKeyBoardBtn = YES;
_textView.delegate = self;
return _textView;
}
- (UILabel *)placeHolder {
if (_placeHolder) {
return _placeHolder;
}
_placeHolder = [[UILabel alloc] initWithFrame:CGRectZero];
_placeHolder.font = [UIFont systemFontOfSize:18];
_placeHolder.textColor = [UIColor lightGrayColor];
_placeHolder.text = @"请输入相应的内容";
_placeHolder.textAlignment = NSTextAlignmentLeft;
return _placeHolder;
}
viewDidload中完成相应的添加与布局
- (void)viewDidload {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"第二种解决办法";
self.navigationController.navigationBar.translucent = NO;
[self.view addSubview:self.textView];
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.top.equalTo(@0);
make.height.equalTo(@300);
}];
[self.textView addSubview:self.placeHolder];
[self.placeHolder mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.textView).offset(15);
make.top.equalTo(self.textView).offset(25);
make.width.greaterThanOrEqualTo(@0);
make.height.greaterThanOrEqualTo(@0);
}];
}
通过UITextViewDelegate协议中的textViewDidChange方法来控制label的显示与隐藏
- (void)textViewDidChange:(UITextView *)textView {
if (textView.text.length > 0) {
self.placeHolder.hidden = YES;
} else {
self.placeHolder.hidden = NO;
}
}
最终的效果图为:
添加UILabel的最终效果图
这种解决办法可以很好的符合我们的需求,但是通用性不是太好,后面每次使用UITextView时,都得为它们添加一个对应的label
3.使用自定义的UITextView添加占位文字(第一种实现方法)
对应的实现文件为XMYPlaceHolderTextView和ThirdSolutionViewController
该方面参考的是简书上的一位作者的文章,相应的链接为:
参考链接
该方法的思路是在自定义的UITextView的drawRect中根据一些逻辑判断添加相应文字
首先,新建一个继承自UITextView的文件,命名为XMYPlaceHolderTextView
在.h文件中定义两个属性,占位文字和占位文字的颜色,方面后面自定义的赋值
/**占位文字*/
@property (nonatomic, copy) NSString *placeHolder;
/**占位文字颜色*/
@property (nonatomic, strong) UIColor *placeHolderColor;
在- (instancetype)initWithFrame:(CGRect)frame方法中,添加关于文字变化的监听
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
//设置默认字体
self.font = [UIFont systemFontOfSize:15];
//设置默认字体颜色
self.placeHolderColor = [UIColor grayColor];
//使用通知监听文字变化
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidChange:) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
}
每次文字发生变化会发出通知,调用方法textViewDidChange:
- (void)textViewDidChange:(NSNotification *)notification {
//该方法会重新走一遍drawRect方法,实现刷新的效果
[self setNeedsDisplay];
}
在drawRect中,我们将占位文字添加上去,这也是这种方法的核心,使用drawInRect:WithAttributes方法实现,(在后面介绍的第四中方法中,区别在于第四种方法是直接添加了UILabel,之后在自定义的textView中控制显示和隐藏,相比于第二种方法,通用性更好)
- (void)drawRect:(CGRect)rect {
//如果有文字,那么占位文字不需要显示,直接返回
if (self.hasText) {
return;
}
//属性
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
attrs[NSFontAttributeName] = self.font;
attrs[NSForegroundColorAttributeName] = self.placeHolderColor;
//计算相应的边框,画出,用于放置文字
rect.origin.x = 15;
rect.origin.y = 25;
rect.size.width -= 2 * rect.origin.x;
[self.placeHolder drawInRect:rect withAttributes:attrs];
}
之后,在属性的setter方法中添加[self setNeedsDisplay];
因为每次赋值可能会导致界面变化,所以需要重新调用drawRect
- (void)setPlaceHolder:(NSString *)placeHolder {
_placeHolder = [placeHolder copy];
[self setNeedsDisplay];
}
- (void)setPlaceHolderColor:(UIColor *)placeHolderColor {
_placeHolderColor = placeHolderColor;
[self setNeedsDisplay];
}
- (void)setFont:(UIFont *)font {
[super setFont:font];
[self setNeedsDisplay];
}
之后,在ThirdSolutionViewController中
//使用自定义UITextView
@property (nonatomic, strong) XMYPlaceHolderTextView *textView;
懒加载以及相应的布局
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"第三种解决办法";
self.navigationController.navigationBar.translucent = NO;
[self.view addSubview:self.textView];
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.right.equalTo(self.view);
make.height.equalTo(@300);
}];
}
- (XMYPlaceHolderTextView *)textView {
if (_textView) {
return _textView;
}
_textView = [[XMYPlaceHolderTextView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 300)];
_textView.backgroundColor = [UIColor greenColor];
_textView.font = [UIFont systemFontOfSize:18];
_textView.textColor = [UIColor whiteColor];
_textView.textContainerInset = UIEdgeInsetsMake(25, 10, 10, 10);
_textView.placeHolderColor = [UIColor lightGrayColor];
_textView.shouldShowHideKeyBoardBtn = YES;
_textView.placeHolder = @"请输入相应的内容";
return _textView;
}
最终的效果图为:
最终效果图.png
这种方法,通用性比较好,后面再遇到类似UITextView的都可以使用
4.自定义UITextView实现placeHolder(第二种方法)
相应的实现文件为FourthSolutionViewController和XMYPlaceHolderNewTextView
这种方法和第三中方法中的区别是自定义UITextView中添加placeHolder是通过添加label实现的,其他的代码大致相同,下面只写XMYPlaceHolderNewTextView的实现
在.h文件中定义相应的属性
@property (nonatomic, copy) NSString *placeHolder;
@property (nonatomic, strong) UIColor *placeHolderColor;
@property (nonatomic, strong) UIFont *labelFont;
在.m文件中
@property (nonatomic, strong) UILabel *label;//用于展示placeHolder
懒加载
- (UILabel *)label {
if (_label) {
return _label;
}
_label = [[UILabel alloc] initWithFrame:CGRectMake(5, 8, CGRectGetWidth(self.bounds) - 10, 15)];
_label.font = [UIFont systemFontOfSize:18];
_label.textColor = [UIColor lightGrayColor];
_label.textAlignment = NSTextAlignmentLeft;
_label.text = @"此处输入默认占位文字";
return _label;
}
在初始化方法中,添加对文字改变的监听
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.label];
//使用通知监听文字改变
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
}
//根据textView中是否有文字来控制label是否显示
- (void)textDidChange:(NSNotification *)notification {
if (self.hasText) {
self.label.hidden = YES;
} else {
self.label.hidden = NO;
}
}
之后根据文字内容使label的大小适应长度
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
setter方法改变label的属性
- (void)setPlaceHolder:(NSString *)placeHolder {
_placeHolder = placeHolder;
self.label.text = placeHolder;
}
- (void)setPlaceHolderColor:(UIColor *)placeHolderColor {
_placeHolderColor = placeHolderColor;
self.label.textColor = placeHolderColor;
}
- (void)setLabelFont:(UIFont *)labelFont {
_labelFont = labelFont;
self.label.font = labelFont;
}
最终的效果图为:
最终效果图
这种方法,通用性比较好,后面再遇到类似UITextView的都可以使用
5.利用运行时特性给UITextView添加placeHolder占位文字
这种方法参考的简书的一篇文章,相应的链接为:
参考链接
对应的实现文件为FifthSolutionViewController
首先,我们需要先查找一下UITextView是否有placeHolder这个私有属性
在viewDidload中
//通过运行时,我们会发现UITextView有一个叫做"_placeHolderLabel"的变量
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([UITextView class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
NSString *objcName = [NSString stringWithUTF8String:name];
NSLog(@"%d : %@",i,objcName);
}
通过运行时,我们发现UITextView是有一个叫做“_placeHolderLabel“的属性
之后我们可以通过运行时给其复制
- (void)setupTextView {
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 300)];
textView.shouldShowHideKeyBoardBtn = YES;
[textView setBackgroundColor:[UIColor greenColor]];
[textView setFont:[UIFont systemFontOfSize:18.f]];
[self.view addSubview:textView];
UILabel *placeHolderLabel = [[UILabel alloc] init];
placeHolderLabel.text = @"请输入相应的内容";
placeHolderLabel.numberOfLines = 0;
placeHolderLabel.textColor = [UIColor lightGrayColor];
[placeHolderLabel sizeToFit];
/*
必须得加这句话,不然的话显示不出来
*/
[textView addSubview:placeHolderLabel];
[textView setFont:[UIFont systemFontOfSize:18.f]];
placeHolderLabel.font = [UIFont systemFontOfSize:18.f];
[textView setValue:placeHolderLabel forKey:@"_placeholderLabel"];
}
最终的效果图为:
效果图
从上面的图中可以看出,存在一些问题,当UITextView设置了contentInset时,无法设置placeHolderLabel距离左边的间距
placeHolderLabel没有设置文字距离左边间距的属性,我们可以通过自定义的label来实现这个功能
新建一个继承UILabel的文件,命名为customLabel
在customLabel.h中定义属性UIEdgeInsets,这样我们可以通过这个属性设置文字距离左边的边距
在customLabel.m中,
- (void)drawTextInRect:(CGRect)rect {
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.edgeInsets)];
}
之后,将placeHolderlabel替换为custonLabel,并设置edgeInsets属性,最终的效果图为:
最终效果图
网友评论