自定义textView,从理论上讲很简单,根据需求自定义,比如我在开发中的需求就是现实一个字数的限制以及根据输入的文字改变提示剩余字数,那么开始我的基本思路就是自定义一个View,而里面包含一个子控件textView以及占位label和剩余字数现实label,看似很简单但是实际上会遇到很多坑!那么我就首先呢从创建这个自定义textView开始,然后在深入讲讲我在这之中遇到的问题和坑。。
在头文件中我是这样申明的:
/**
* 占位符
*/
@property (nonatomic, copy)NSString *placeholder;
@property (nonatomic, strong)UILabel *placehoderLabel;
/**
* 限制的文字
*/
@property (nonatomic, copy)NSString *limitStr;
/**
* 剩余字数
*/
@property (nonatomic, assign)NSInteger count;
@property (nonatomic, strong)UILabel *countLabel;
@property (nonatomic, weak)id<UITextViewDelegate> textViewDelegate;
@property (nonatomic, strong)UITextView *textView;
在头文件中我公开了很多属性,比如placehoderLabel, textView,countLabel等等,在这我想说明一件事情,这件事情也是我在公司和一位同事意见不合的问题,我认为一切有变化的因子,都应该留出接口让别人能够改变,意思也就是说,在我们自定义一个控件的时候,为了可以让更多的人使用以及复用性,我们一定要留出变化的接口,这样在别人复用的时候,就不用再去内部改变,而只是根据接口去改变这些需要改变的内容即可。
下面贴上我的整个实现代码:
@implementation YHTextView
- (NSString *)placeholder {
if (_placeholder == nil) {
_placeholder = @"请输入文字";
}
return _placeholder;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.layer.borderColor = [UIColor lightGrayColor].CGColor;
self.layer.borderWidth = 1.f;
_count = 50;
self.countLabel.text = @"剩余50字";
self.textView.height = self.height - 25;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewCharacterChanged:) name:UITextViewTextDidChangeNotification object:nil];
}
return self;
}
- (UITextView *)textView {
if (_textView == nil) {
_textView = [[UITextView alloc] init];
_textView.frame = CGRectMake(0, 0, self.width, self.height);
_textView.delegate = self.textViewDelegate;
_textView.font = TK_FONTSYS(14);
[self addSubview:_textView];
}
return _textView;
}
- (UILabel *)placehoderLabel {
if (_placehoderLabel == nil) {
_placehoderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 8, 20, 20)];
_placehoderLabel.text = self.placeholder;
_placehoderLabel.textAlignment = NSTextAlignmentLeft;
_placehoderLabel.font = [UIFont systemFontOfSize:14];
_placehoderLabel.textColor = [UIColor lightGrayColor];
[self.textView addSubview:_placehoderLabel];
}
[self sendSubviewToBack:_placehoderLabel];
return _placehoderLabel;
}
- (UILabel *)countLabel {
if (_countLabel == nil) {
_countLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.width-5-100, self.height-5-20, 100, 20)];
_countLabel.textAlignment = NSTextAlignmentRight;
_countLabel.font = [UIFont systemFontOfSize:13];
_countLabel.textColor = [UIColor lightGrayColor];
[self addSubview:_countLabel];
}
return _countLabel;
}
- (void)layoutSubviews {
self.placehoderLabel.frame = CGRectMake(8, 8, self.width, 20);
if (self.textView.text.length>0) {
self.placehoderLabel.hidden = YES;
self.countLabel.text = [NSString stringWithFormat:@"剩余%ld字", self.count - self.textView.text.length];
self.placehoderLabel.hidden = YES;
}
}
- (void)textViewCharacterChanged:(NSNotification *)not {
NSInteger length = self.textView.text.length;
self.placehoderLabel.hidden = YES;
// 获取键盘类型
UITextInputMode *mode = (UITextInputMode *)[UITextInputMode activeInputModes][0];
// 获取当前的键盘语言
NSString *lang = mode.primaryLanguage;
if ([lang isEqualToString:@"zh-Hans"]) {
UITextRange *selectedRange = [self.textView markedTextRange];
UITextPosition *position = [self.textView positionFromPosition:selectedRange.start offset:0];
if (!position) {
if ([self beyondLimitCount:length]) return ;
if (length == 0) {
self.countLabel.text = @"剩余50字";
self.placehoderLabel.hidden = NO;
}
else {
self.countLabel.text = [NSString stringWithFormat:@"剩余%ld字", self.count - length];
self.placehoderLabel.hidden = YES;
}
}
}
else {
if ([self beyondLimitCount:length]) return ;
if (length == 0) {
self.countLabel.text = @"剩余50字";
self.placehoderLabel.hidden = NO;
}
else {
self.countLabel.text = [NSString stringWithFormat:@"剩余%ld字", self.count - length];
self.placehoderLabel.hidden = YES;
}
}
}
- (BOOL)beyondLimitCount:(NSInteger)length {
if (length <= self.count) {
self.textView.editable = YES;
return NO;
}
else {
self.textView.text = [self.textView.text substringToIndex:self.count];
self.countLabel.text = @"剩余0字";
return YES;
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
1>第一点需要注意的是,添加通知和移除通知是必须配对的,我们一般在dealloc方法里移除通知
2>在我的代码中很多控件都是懒加载的方式初始化的,这也是苹果比较推荐的一种方式,懒加载即是控件需要显示的时候加载
3>核心代码都在通知方法里,首先我们需要获取键盘类型,从而获得当前的语言,注意是汉字的话要进行特殊处理,因为汉字在输入的时候有一个高亮状态如果,不作处理,如果说剩余2个字,你想在输入“行”拼音是“xing”,就会只输入xi,无法得到汉字,这也是我遇到比较坑的一个地方。
至于其他部分都是一些比较简单的逻辑处理,在这里就不再做说明了。