封装一个自适应高度的 textview
2015-10-25 15:49
871 查看
这期做组内项目的时候需要用到一个可以自适应高度的textview,类似微信的输入框那样的。有时候又需要在textview里面添加一些提示性的placeholder,但是系统自带的textview不同于UITextFiled,没有placeholder属性的,这就需要我们自定义做一个placeholder,我的做法是在textview上面添加一个label,当开始编辑的时候将其隐藏,在一开始创建就未初始化placeholderString的时候则不创建这个label。
首先,确定下需要提供给外部使用的功能,能够自定义的字体上下间距up_LowSpace,最大字数maxWorlds,最小字数minWorlds,最大高度maxHei,最小高度minHei,通过定义了三个不同功能的block,提供多个block回调方法,可以实现更多自定义功能。同时还可以提供字数统计,能自定义字数统计的文案和字数的字体和颜色,以及实时提示当前已输入字数:@“您已输入xx字”或者还可输入的字数:@“您还可以输入xx字”。
总结下功能如下:
1/带有沉底文字和字数统计,可以自定义沉底文字的样式,字数统计的frame;
2/自定义textview最大高度和宽度,还可以让textview根据输入的字数多少动态改变高度;
3/自定义可以输入的最大字数,当达到最大字数的时候通过block回调自定义动作;
4/提供多个对外多block接口,支持多种情况下的操作,例如,开始编辑的时候,结束编辑的时候。
另:
textview的几个代理方法
输入过程中,方法顺序大致为:
1/
好,上代码:
AHTextView.h文件
AHTextView.h文件
实现初始化类方法:
定义并实现自己定义的initWith方法,记得调用[super init],最后调用自定义的创建textview的方法
- (void)initialzeTextViewWithFrame: textAttribute: up_LowSpace: placeholderString: placeholderAttribute: cornerRadius:
实现textview的初始化方法,如果有设置placehoderString,则在textview上面添加一个label用于显示沉底文字,否则不创建label:
接下来,根据placehoderstring和placeholderattribute创建placehoderlabel,并将label添加到textveiw上面去
创建字数统计label
所以的UI都创建完毕,接下来在添加 UITextViewDelegate,并实现代理方法。由于最开头就介绍过了各个代理方法的主要作用,这里主要给的是根据输入的文字自适应textview的高度
详细的代码可以查看https://github.com/hah1992/AHTextView
首先,确定下需要提供给外部使用的功能,能够自定义的字体上下间距up_LowSpace,最大字数maxWorlds,最小字数minWorlds,最大高度maxHei,最小高度minHei,通过定义了三个不同功能的block,提供多个block回调方法,可以实现更多自定义功能。同时还可以提供字数统计,能自定义字数统计的文案和字数的字体和颜色,以及实时提示当前已输入字数:@“您已输入xx字”或者还可输入的字数:@“您还可以输入xx字”。
总结下功能如下:
1/带有沉底文字和字数统计,可以自定义沉底文字的样式,字数统计的frame;
2/自定义textview最大高度和宽度,还可以让textview根据输入的字数多少动态改变高度;
3/自定义可以输入的最大字数,当达到最大字数的时候通过block回调自定义动作;
4/提供多个对外多block接口,支持多种情况下的操作,例如,开始编辑的时候,结束编辑的时候。
另:
textview的几个代理方法
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView; //return YES:开始编辑 return NO:不允许编辑
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView; //return YES:开始编辑 return NO:不允许编辑
- (void)textViewDidBeginEditing:(UITextView *)textView; //已经开始编辑
- (void)textViewDidEndEditing:(UITextView *)textView; //已经结束编辑
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; //这个方法是讲你即将输入的字符放入textview中去处理, //return YES:允许输入,也就是将你原来最后一个字符替换为你即将输入的字符 return NO:不允许输入,此时无论你键盘如何输入,textview中的text都是不会改变的。
- (void)textViewDidChangeSelection:(UITextView *)textView; //这个方法不是很了解具体是什么意思,大概的意思是移动光标位置
- (BOOL)textViewShouldEndEditing:(UITextView *)textView; //return YES:结束编辑 return NO:不允许结束编辑
- (void)textViewDidChange:(UITextView *)textView; //textview中的text已经发生了改变
输入过程中,方法顺序大致为:
1/
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;2/
- (void)textViewDidChangeSelection:(UITextView *)textView;3/
- (void)textViewDidChange:(UITextView *)textView;
好,上代码:
AHTextView.h文件
#import <UIKit/UIKit.h> @class AHTextView; typedef BOOL (^shouldBlock) (AHTextView *textView); typedef void (^didBlock) (AHTextView *textView); typedef void (^changeHeightBlock) (AHTextView *textView,CGFloat height); @interface AHTextView : UIView @property (nonatomic,assign) CGFloat up_LowSpace;//字体上下间距 @property (nonatomic,assign) CGFloat maxWorlds; //最多字数 @property (nonatomic,assign) CGFloat minWorlds; //最少字数 @property (nonatomic,assign) CGFloat maxHei; //最大高度 @property (nonatomic,assign) CGFloat minHei; //最小高度 /** * textview delegate方法block */ @property (nonatomic,assign) shouldBlock shouldBeginEditing; @property (nonatomic,assign) shouldBlock shouldEndEditing; @property (nonatomic,assign) didBlock didChangeSelection; @property (nonatomic,assign) didBlock didBeginEditing; @property (nonatomic,assign) didBlock didEndEditing; @property (nonatomic,assign) didBlock textDidChanged; @property (nonatomic,assign) didBlock comeToMaxWorlds;//达到最大字数自动方法block @property (nonatomic,assign) didBlock tapReturn; //点击回车键自定方法block @property (nonatomic,assign) changeHeightBlock changeHeightOption;//高度改变block /** @pram placeholderString:沉底文字 @pram placeholderAttribute:沉底文字属性 @pram cornerRadius:圆角半径,小于零将被设置为圆形 */ + (instancetype)createTextViewWithFrame: (CGRect)frame backgroundColor: (UIColor *)color backImageName: (NSString *)imgName textAttribute: (NSMutableDictionary *)textAttribute up_LowSpace: (CGFloat)up_LowSpace maxWorlds: (CGFloat)maxWorlds minWorlds: (CGFloat)minWolrds maxHeight: (CGFloat)maxHei minHeight: (CGFloat)minHei placeholderString: (NSString *)placeholderString placeholderAttribute: (NSMutableDictionary *)placeholderAttribute cornerRadius: (CGFloat)cornerRadius; @end
AHTextView.h文件
实现初始化类方法:
+ (instancetype)creatTextVeiwWithFrame: (CGRect)frame backgroundColor: (UIColor *)color backImageName: (NSString *)imgName textAttribute: (NSMutableDictionary *)textAttribute up_LowSpace: (CGFloat)up_LowSpace maxWorlds: (CGFloat)maxWorlds minWorlds: (CGFloat)minWolrds maxHeight: (CGFloat)maxHei minHeight: (CGFloat)minHei placeholderString: (NSString *)placeholderString placeholderAttribute: (NSMutableDictionary *)placeholderAttribute cornerRadius: (CGFloat)cornerRadius { return [[self alloc] initWithFrame:frame backgroundColor:color backImageName:imgName textAttribute:textAttribute up_LowSpace:up_LowSpace maxWorlds:maxWorlds minWorlds:minWorlds maxHeight:maxHei minHeight:minHei placeholderString:placeholderString placeholderAttribute:placeholderAttribute cornerRadius: (CGFloat)cornerRadius]; }
定义并实现自己定义的initWith方法,记得调用[super init],最后调用自定义的创建textview的方法
- (void)initialzeTextViewWithFrame: textAttribute: up_LowSpace: placeholderString: placeholderAttribute: cornerRadius:
- (instancetype)initWithFrame: (CGRect)frame backgroundColor: (UIColor *)color backImageName: (NSString *)imgName 4000 textAttribute: (NSMutableDictionary *)textAttribute up_LowSpace: (CGFloat)up_LowSpace maxWorlds: (CGFloat)maxWorlds minWorlds: (CGFloat)minWolrds maxHeight: (CGFloat)maxHei minHeight: (CGFloat)minHei placeholderString: (NSString *)placeholderString placeholderAttribute: (NSMutableDictionary *)placeholderAttribute cornerRadius: (CGFloat)cornerRadius { //计算一行的高度 NSString *tempContent = @"hah"; UIFont *textFont = [textAttribute objectForKey:NSFontAttributeName]; NSDictionary *tempAttr; //设置了字体大小就使用自定义的,否则使用默认值15.0f if (textFont) { tempAttr = @{NSFontAttributeName:textFont}; } else { tempAttr = @{NSFontAttributeName:[UIFont systemFontOfSize:15.0f]}; } CGSize textSize = [tempContent boundingRectWithSize:CGSizeMake(frame.size.width, maxHei) options:NSStringDrawingUsesFontLeading attributes:tempAttr context:nil].size; // 只有单行时,textview的高度 CGFloat singleLineH = textSize.height + 2*up_LowSpace; if (minHei < singleLineH) { minHei = singleLineH; } //根据最大最小高度调整frame.size.height if (frame.size.height < minHei) { frame.size.height = minHei; } else if (frame.size.height <= maxHei) { minHei = frame.size.width; } else { frame.size.height = maxHei; } //处理最大最小字数 if (minWolrds < 0) { minWolrds = 0; } else if (maxWorlds < minWolrds) { maxWorlds = minWolrds + 20; } self = [super initWithFrame:frame]; if (self) { self.backgroundColor = color; self.maxWorlds = maxWorlds; self.minWolrds = minWolrds; self.maxHei = maxHei; self.minHei = minHei; [self initialzeTextViewWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) textAttribute:textAttribute up_LowSpace:up_LowSpace placeholderString:placeholderString placeholderAttribute:placeholderAttribute cornerRadius:cornerRadius]; } return self; }
实现textview的初始化方法,如果有设置placehoderString,则在textview上面添加一个label用于显示沉底文字,否则不创建label:
- (void)initialzeTextViewWithFrame: (CGRect)frame textAttribute: (NSMutableDictionary *)textAttribute up_LowSpace: (CGFloat)up_LowSpace placeholderString: (NSString *)placeholderString placeholderAttribute: (NSMutableDictionary *)placeholderAttribute cornerRadius: (CGFloat)cornerRadius { UITextView *textView = [[UITextView alloc] initWithFrame:frame]; //根据属性字典设置字体属性,取不到的情况下使用默认值:黑色 15号 UIFont *textFont = [textAttribute objectForKey:NSFontAttributeName]; UIColor *textColor = [textAttribute objectForKey:NSForegroundColorAttributeName]; if (textFont) { textView.font = textFont; } else { textView.font = [UIFont systemFontOfSize:15]; } if (textColor) { textView.textColor = textColor; } else { textView.textColor = [UIColor blackColor]; } //设置上下间距 textView.textContainerInset = UIEdgeInsetsMake(up_LowSpace, 0, up_LowSpace, 0); textView.backgroundColor = [UIColor whiteColor]; //小于0设置为圆形 cornerRadius = cornerRadius < 0? frame.size.height/2:cornerRadius; textView.layer.cornerRadius = cornerRadius; textView.layer.masksToBounds = YES; textView.delegate = self; [self addSubview:textView]; //有placeholderString才创建label if (placeholderString && ![placeholderString isEqualToString:@""] && ![placeholderString isEqualToString:@" "]) { [self initialzePlaceholderViewWithString:placeholderString stringAttribute:placeholderAttribute superView:textView]; } self.textView = textView; }
接下来,根据placehoderstring和placeholderattribute创建placehoderlabel,并将label添加到textveiw上面去
#pragma mark placehloder - (void)initialzePlaceholderViewWithString: (NSString *)placeholderString stringAttribute: (NSMutableDictionary *)placeholderAttribute superView: (UIView *)superView { UILabel *label = [[UILabel alloc] init]; CGRect textRect = self.textView.frame; label.frame = CGRectMake(5, textRect.origin.y, textRect.size.width - 5, textRect.size.height); label.backgroundColor = [UIColor clearColor]; label.numberOfLines = 0; UIFont *textFont = [placeholderAttribute objectForKey:NSFontAttributeName]; UIColor *textColor = [placeholderAttribute objectForKey:NSForegroundColorAttributeName]; if (textFont) { label.font = textFont; } else { label.font = [UIFont systemFontOfSize:15]; } if (textColor) { label.textColor = textColor; } else { label.textColor = [UIColor grayColor]; } //将placeholder显示文字置顶 CGFloat totalHeight = [placeholderString boundingRectWithSize:label.frame.size options:NSStringDrawingTruncatesLastVisibleLine attributes:placeholderAttribute context:nil].size.height; CGFloat singleHeight = [placeholderString boundingRectWithSize:label.frame.size options:NSStringDrawingUsesFontLeading attributes:placeholderAttribute context:nil].size.height; NSUInteger lineCount = (label.frame.size.height - totalHeight)/ singleHeight ; for (int i = 0; i < lineCount; i ++) { placeholderString = [placeholderString stringByAppendingString:@"\n "]; } label.text = placeholderString; label.hidden = NO; [superView addSubview:label]; self.placeholderLabel = label; }
创建字数统计label
#warning word count - (void)initialzeWordsCountLabelWithFrame: (CGRect)countFrame stringAttribute: (NSMutableDictionary *)countAttr{ UILabel *countLabel = [[UILabel alloc] initWithFrame:countFrame]; [countLabel setBackgroundColor:[UIColor clearColor]]; if (!countAttr) { countAttr = [NSMutableDictionary dictionaryWithDictionary:@{NSForegroundColorAttributeName:[UIColor grayColor],NSFontAttributeName:[UIFont systemFontOfSize:12]}]; } self.wordsCountAttribute = countAttr; NSMutableAttributedString *attributeStr = [[NSMutableAttributedString alloc] initWithString:@"您已输入0个字" attributes:countAttr]; [attributeStr addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:0.6 green:0 blue:0 alpha:1] range:NSMakeRange(4, 1)]; countLabel.attributedText = attributeStr; UIFont *textFont = [countAttr objectForKey:NSFontAttributeName]; UIColor *textColor = [countAttr objectForKey:NSForegroundColorAttributeName]; if (textFont) { self.countFont = textFont; } else { self.countFont = [UIFont systemFontOfSize:12]; } if (textColor) { self.countColor = textColor; } else { self.countColor = [UIColor grayColor]; } self.wordsCountLabel = countLabel; [self addSubview:countLabel]; CGRect lineFrame = countFrame; lineFrame.origin.x = self.bounds.origin.x; lineFrame.origin.y = countFrame.origin.y + countFrame.size.height+1; lineFrame.size.width = self.frame.size.width; lineFrame.size.height = 0.5; UIView *line = [[UIView alloc] initWithFrame:lineFrame]; line.backgroundColor = [UIColor grayColor]; [self addSubview:line]; }
所以的UI都创建完毕,接下来在添加 UITextViewDelegate,并实现代理方法。由于最开头就介绍过了各个代理方法的主要作用,这里主要给的是根据输入的文字自适应textview的高度
//动态计算高度 #pragma mark 高度调整 //获取textview中的文本输入框高度 CGFloat textContainerHei = [[self.textView layoutManager] usedRectForTextContainer:self.textView.textContainer].size.height + 2*self.up_LowSpace ; // 获取textview的实际高度 CGRect textFrame = self.textView.frame ; if (textContainerHei < self.minHei) { textFrame.size.height = self.minHei; }else if (textContainerHei > self.maxHei){ textFrame.size.height = self.maxHei; }else{ textFrame.size.height = textContainerHei; } //获取自身大小 [UIView animateWithDuration:0.25 animations:^{ self.textView.frame = textFrame; CGRect rect = self.frame; if (self.wordsCountLabel) { if (self.upwoardExtension) { rect.origin.y = self.baseline - textFrame.size.height; } rect.size.height = textFrame.size.height + self.wordsCountHei; NSLog(@"%@",NSStringFromCGRect(self.frame)); }else{ rect.size.height = textFrame.size.height; } self.frame = rect;
详细的代码可以查看https://github.com/hah1992/AHTextView
相关文章推荐
- 社交巨头三国杀:微信、WhatsApp、Line到底有啥区别?
- 微信悄悄升级群聊功能:个人微信营销号的福音
- 我是运营,我没有假期
- 如何做到日消息量100万的微信公众号?
- 论微信取消推送功能的可能性(原创)
- 微信的成功,靠的是QQ导流吗?
- flash 系统字体显示问题
- 微信服务号推送模板消息接口
- C#及WPF获取本机所有字体和颜色的方法
- 谈谈网页设计中的字体应用Font Set
- PDF里的文字显示模糊的解决方法
- 保证可下载的漂亮动作2008奥运比赛项目字体
- C#实现字体旋转的方法
- 网页设计中的 serif 和 sans-serif字体应用
- Android的TextView与Html相结合的具体方法
- Android中实现为TextView添加多个可点击的文本
- PHP限制页面只能在微信自带浏览器访问的代码