UITextView继承UIScrollView,所以也有scrollView的属性
总体的结构是这样的:
textview里面有一个textContainer,这个可以理解为一个内容的容器,用来显示内容的
现在来理解contentInset,就是textContainer距离四周的margin;而textContainerInset就是textContainer的padding;
所以,textView的整体结构是
textView.width = contentInset.right + contentInset.left +textView.textContainer.right + textView.textContainer.left + textView.textContainer.lineFragmentPadding * 2(text的左右边距) + text.width;
textView.height = contentInset.top + contentInset.bottom + textView.textContainer.top + textView.textContainer.bottom;
我实现textView动态计算高度的方法如下:
1.使用sizeThatFits计算高度
这个高度是整个textView的高度,默认textContainer.height = textContainer.bottom = 8
所以,如果设置contentInset = UIEdgeInsetsZero,字体为font = 15,则输入框的第一行多显示高度:
height = ceil([UIFont systemFontOfSize: 15].lineHeight + myTextView.textContainerInset.top + myTextView.textContainerInset.bottom)
高度改变的动作发生在:
- (void)textViewDidChange:(UITextView *)textView
计算整个textView的size
size = [textView sizeThatFits: CGSizeMake(textView.frame.size.width, BMuMaxHeight)]; //BMuMaxHeight =height * 6,为最大的高度,我这里显示6行
每次换行都时候,动态改变textView的高度,当前行:
currentRow = round(textViewContentHeight / [UIFont systemFontOfSize: 15].lineHeight)
改变textView高度:
CGRect textViewFrame = textView.frame;
myTextView.frame = CGRectMake(textViewFrame.origin.x, textViewFrame.origin.y, textViewFrame.size.width, textViewContentHeight);
2.使用boundingRectWithSize计算高度
使用这个函数计算textView的高度会有问题
第一:一般换行了几个字符才算第二行的高度
第二:如果输入字符过快有时候会计算几次的高度
CGSize size = [textView.text boundingRectWithSize: CGSizeMake(textView.frame.size.width, MAXFLOAT) options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes: @{NSFontAttributeName: [UIFont systemFontOfSize: 15]} context: nil].size;
if (size.height > BMuMaxHeight) {
return;
}
[UIView animateWithDuration: 0.3 animations:^{
inputBar.frame = CGRectMake(0, BMuScreenHeight - keyboardRect.size.height - (size.height + 26), BMuScreenWidth, size.height + 26);
myTextView.frame = CGRectMake(10, 5, myTextView.frame.size.width, size.height + 16);
} completion:^(BOOL finished) {
}];
3.使用contentSize计算高度
使用contentsize计算高度会跳跃,计算不准
- (void)textViewDidChange:(UITextView *)textView {
CGSize size = textView.contentSize;
if (size.height > BMuMaxHeight) {
return;
}
[UIView animateWithDuration: 0.3 animations:^{
inputBar.frame = CGRectMake(0, BMuScreenHeight - keyboardRect.size.height - (size.height + 10), BMuScreenWidth, size.height + 10);
myTextView.frame = CGRectMake(10, 5, myTextView.frame.size.width, size.height);
} completion:^(BOOL finished) {
}];
}
4.使用[myTextView.layoutManager usedRectForTextContainer: myTextView.textContainer].size
(void)textViewDidChange:(UITextView *)textView {
CGSize size = [myTextView.layoutManager usedRectForTextContainer: myTextView.textContainer].size;
float rows = ceil(size.height / myTextView.font.lineHeight);
if (rows >= 6) {
return;
}CGFloat height = ceil(size.height - myTextView.font.lineHeight);
if (number != rows) {
[UIView animateWithDuration: 0.3 animations:^{
inputBar.frame = CGRectMake(0, BMuScreenHeight - keyboardRect.size.height - (height + 44), BMuScreenWidth, height + 44);
myTextView.frame = CGRectMake(10, 5, myTextView.frame.size.width, 34 + height);
} completion:^(BOOL finished) {
}];
number = rows;
}
}
5.动态布局,纯代码推荐用Masonry.h
Notice: 在达到最大高度之前,ios7和ios8要注意换行时,滚动的问题,ios9换行不会滚动