iOS开发小技巧--自定义带有占位文字的TextView(两种方式)

时间:2022-01-27 20:11:23

自定义控件注意或框架注意:自己暴露在外面的属性,一定要重写setter,保证外界与内部的交互性

一.方案一:通过drawRect:方法将文字画到textView中,监听文字改变用的是通知中心(代理也可以监听文字改变,但是这种方式就成了自己作为自己的代理了,不推荐这种方法)发出的消息

UITextViewTextDidChangeNotification.自己监听通知.

  • 对外界提供两个属性

iOS开发小技巧--自定义带有占位文字的TextView(两种方式)

  • 内部实现
 #import "ChaosPlaceholdTextView.h"

 @implementation ChaosPlaceholdTextView

 - (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextViewTextDidChangeNotification object:nil]; // 外界文字颜色不设置,默认为灰色
self.placeholdColor = [UIColor grayColor];
}
return self;
} - (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
} - (void)textChange
{
[self setNeedsDisplay];
} // 调用drawRect时,会将之前的图像擦除掉,重新绘制
- (void)drawRect:(CGRect)rect { if ([self hasText]) return; rect.origin.y += ( + );
rect.origin.x += ;
rect.size.width -= * rect.origin.x; NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
attrs[NSForegroundColorAttributeName] = self.placeholdColor;
attrs[NSFontAttributeName] = [UIFont systemFontOfSize:];
[self.placehold drawInRect:rect withAttributes:attrs];
} // 设计框架需注意,给外界提供了属性后,一定重写出行的setter,这样既可以时时监听使用者对属性的更改,还可以跟好的与外界代码进行交互
- (void)setPlacehold:(NSString *)placehold
{
_placehold = placehold;
// 设置了站位文字后,需要重绘一遍
[self setNeedsDisplay];
} - (void)setPlaceholdColor:(UIColor *)placeholdColor
{
_placeholdColor = placeholdColor;
[self setNeedsDisplay];
} // 同时,也要考虑到
- (void)setFont:(UIFont *)font
{
[super setFont:font]; [self setNeedsDisplay];
} - (void)setText:(NSString *)text
{
[super setText:text]; [self setNeedsDisplay];
} - (void)setAttributedText:(NSAttributedString *)attributedText
{
[super setAttributedText:attributedText]; [self setNeedsDisplay];
} @end
  • 缺点:由于是画上去的,当设置了textView的alwaysBounceHorizontal属性后,不能跟随着scrollView的滑动而滑动,如下图

iOS开发小技巧--自定义带有占位文字的TextView(两种方式)

方案二:通过给TextView添加一个Label,也是通过监听文字改变的通知,修改label的hidden属性.

 #import "ChaosPlaceholdTextView.h"

 @interface ChaosPlaceholdTextView()
/** 占位文字label */
@property (nonatomic, weak) UILabel *placeholderLabel;
@end @implementation ChaosPlaceholdTextView - (UILabel *)placeholderLabel
{
if (!_placeholderLabel) {
// 添加一个用来显示占位文字的label
UILabel *placeholderLabel = [[UILabel alloc] init];
placeholderLabel.numberOfLines = ;
placeholderLabel.x = ;
placeholderLabel.y = ;
[self addSubview:placeholderLabel];
_placeholderLabel = placeholderLabel;
}
return _placeholderLabel;
} - (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
// 垂直方向上永远有弹簧效果
self.alwaysBounceVertical = YES; // 默认字体
self.font = [UIFont systemFontOfSize:]; // 默认的占位文字颜色
self.placeholderColor = [UIColor grayColor]; // 监听文字改变
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
} - (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
} /**
* 监听文字改变
*/
- (void)textDidChange
{
// 只要有文字, 就隐藏占位文字label
self.placeholderLabel.hidden = self.hasText;
} /**
* 更新占位文字的尺寸
*/
- (void)updatePlaceholderLabelSize
{
CGSize maxSize = CGSizeMake(ChaosScreenW - * self.placeholderLabel.x, MAXFLOAT);
self.placeholderLabel.size = [self.placeholder boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : self.font} context:nil].size;
} #pragma mark - 重写setter
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
_placeholderColor = placeholderColor; self.placeholderLabel.textColor = placeholderColor;
} - (void)setPlaceholder:(NSString *)placeholder
{
_placeholder = [placeholder copy]; self.placeholderLabel.text = placeholder; [self updatePlaceholderLabelSize];
} - (void)setFont:(UIFont *)font
{
[super setFont:font]; self.placeholderLabel.font = font; [self updatePlaceholderLabelSize];
} - (void)setText:(NSString *)text
{
[super setText:text]; [self textDidChange];
} - (void)setAttributedText:(NSAttributedString *)attributedText
{
[super setAttributedText:attributedText]; [self textDidChange];
} @end