本人最近在研究socket與聊天界面的UI,在寫聊天界面UI的時候是模仿微信的界面其中的文字輸入框會隨著字?jǐn)?shù)的多少而自適應(yīng)高度,當(dāng)然超過某個行數(shù)輸入框的高度就不會增加了變?yōu)榭蓾L動,具體效果如下。

我的思路是用約束來實現(xiàn),輸入?yún)^(qū)域用UITextView來實現(xiàn);約束可以使用AutoLayout或者是第三方庫Masonry來實現(xiàn),但是他們的實現(xiàn)原理是一樣的。為了方便我使用了Xib加AutoLayout來實現(xiàn)的,我是根據(jù)UITextView的字?jǐn)?shù),寬度固定來計算出文字的高度,從而實現(xiàn)UITextView的高度自適應(yīng)。
我們都知道一般的聊天軟件的界面(微信為例)輸入框左邊是一個按鈕切換語音或者文字,輸入框右邊是表情符號和切換出發(fā)送照片等功能;當(dāng)然本文主要是介紹輸入框TextView的自適應(yīng),原諒我把其他東西省略了。首先textView需要一個BackVew,我們拖進(jìn)去一個UIview,讓它相對于父視圖居左居右為0,居底部也為0,另外還需要給它一個初始高度,一般情況下是textView是一行文字的高度+textView距離它的頂部距離和底部距離。比如,我讓textView距離它的backView底部與頂部分別是5,textView的字號是系統(tǒng)17號字,那么textView是一行的時候它的高度就是37,而這時候backView的初始高度就是37+5+5=47。textView居底部與頂部分別是5,距離左右的具體可以根據(jù)你們設(shè)計給的UI而定。這里的關(guān)鍵是當(dāng)textView的字?jǐn)?shù)變化時,我們通過計算得到當(dāng)前字?jǐn)?shù)應(yīng)該顯示的高度,我們得到這個值后適當(dāng)?shù)恼{(diào)增backView的高度,因為backView是相對于底部約束,增加高度后就會向上增加,而textView是依據(jù)backView的頂部與底部來約束的所以就會跟隨者backView的高度變化而變化。從而實現(xiàn)textView自適應(yīng)高度。
完后上面的約束之后,我們需要把backView、textView、backView的高度約束以及backView距離底部的約束都拉到代碼中成為屬性。

在viewdidload方法里面實現(xiàn)textView的一些設(shè)置
self.textView.delegate = self;
self.textView.scrollEnabled = NO;
self.textView.scrollsToTop = NO;
self.textView.layer.borderWidth = 1;
self.textView.layer.cornerRadius = 5;
self.textView.font = [UIFont systemFontOfSize:17];
//當(dāng)textview的字符串為0時發(fā)送(rerurn)鍵無效
self.textView.enablesReturnKeyAutomatically = YES;
self.textView.keyboardType = UIKeyboardTypeDefault;
//鍵盤return樣式變成發(fā)送
self.textView.returnKeyType = UIReturnKeySend;
當(dāng)鍵盤升起的時候我們需要調(diào)整backView具體底部的距離,防止鍵盤升起遮擋textView,所以要實現(xiàn)監(jiān)聽鍵盤高度
//監(jiān)聽鍵盤
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardWillChangeFrameNotification object:nil];
實現(xiàn)當(dāng)鍵盤升起或者落下的方法
- (void)keyboardWasShown:(NSNotification*)aNotification {
// 獲取鍵盤彈出時長
CGFloat duration = [aNotification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
//鍵盤高度
CGRect keyBoardFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
//調(diào)增backView距離父視圖底部的距離
_backViewBottomHCons.constant = keyBoardFrame.origin.y != screenH?keyBoardFrame.size.height:0;
[UIView animateWithDuration:duration animations:^{
[self.view layoutIfNeeded];
}];
}
設(shè)置textView的最大高度,這個與你設(shè)置的最大行數(shù)有關(guān)
// 計算最大高度 = (每行高度 * 總行數(shù) + 文字上下間距)
_maxTextH = ceil(self.textView.font.lineHeight * 4 + self.textView.textContainerInset.top + self.textView.textContainerInset.bottom);
實現(xiàn)textView的代理方法,下面的代碼方法是當(dāng)textView的text發(fā)生改變時會調(diào)用,我們可以計算文字的高度,調(diào)整backView的高度。
- (void)textViewDidChange:(UITextView *)textView {
NSInteger height = ceilf([self.textView sizeThatFits:CGSizeMake(self.textView.bounds.size.width, MAXFLOAT)].height);
if (_textOldH!=height) {
// 最大高度,可以滾動
self.textView.scrollEnabled = height > _maxTextH && _maxTextH > 0;
if (self.textView.scrollEnabled==NO) {
_backViewHCons.constant = height + 10;//距離上下邊框各為5,所以加10
[self.view layoutIfNeeded];
}
_textOldH = height;
}
}
我們上面講鍵盤的return鍵設(shè)置了樣式是send,所以當(dāng)用戶再點擊return鍵時不應(yīng)該是換行而是實現(xiàn)send的業(yè)務(wù)邏輯,所以需要實現(xiàn)下面的代理。
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
if (textView==self.textView && [text isEqualToString:@"\n"]){ //判斷輸入的字是否是回車,即按下return
//在這里做你響應(yīng)return鍵的代碼
textView.text = nil;
[self textViewDidChange:textView];
return NO; //這里返回NO,就代表return鍵值失效,即頁面上按下return,不會出現(xiàn)換行,如果為yes,則輸入頁面會換行
}
return YES;
}
總結(jié)一下,這里的關(guān)鍵是當(dāng)textView的字?jǐn)?shù)變化時,我們通過計算得到當(dāng)前字?jǐn)?shù)應(yīng)該顯示的高度,我們得到這個值后適當(dāng)?shù)恼{(diào)增backView的高度,因為backView是相對于底部約束,增加高度后就會向上增加,而textView是依據(jù)backView的頂部與底部來約束的所以就會跟隨者backView的高度變化而變化。從而實現(xiàn)textView自適應(yīng)高度。
這里是demo的下載地址 ,有什么問題歡迎大家指正。另外如果對你有幫助別忘了star。