前言
項目中經(jīng)常會用到UITextView,但是系統(tǒng)的textView在限制多行輸入的時候會出現(xiàn)問題。(過渡動畫很亂)。基于限制多行輸入或者cell跟隨textView內(nèi)容自適應(yīng)的需求,所以自定義一個textView。
自定義textView
關(guān)于textView的一些摸索,iOS仿微信輸入框,限制最大行數(shù),一體鍵盤(兩種思路),這篇文章中有介紹,下面示例會用到。
封裝一個可限制多行輸入的textView,首先屏蔽掉系統(tǒng)對textView的默認設(shè)置_textView.textContainerInset = UIEdgeInsetsZero,屏蔽掉之后可以給textView添加一個上下左右的間距,UIView作為textView的容器。這樣在限制多上輸入的時候動畫過度就會很自然,默認是不限制行數(shù)的。
.h接口的配置:
@property(nonatomic,assign)CGFloat v_margin;//豎直方向上下間距 默認為8;
@property(nonatomic,assign)CGFloat h_margin;//水平方向上下間距 默認為0;
@property(nonatomic,assign)NSInteger initiLine;//初始需要展示的行數(shù) 默認為1;
@property(nonatomic,assign)NSInteger maxLine;//最大行數(shù) 默認為無窮大;
@property(nonatomic,strong)NSString *placeholder;//占位文字
@property(nonatomic,strong)UIFont *font;//默認為17
@property(nonatomic,assign)CGPoint placePoint;//設(shè)置占位符的位置,豎直方向設(shè)置v_margin即可 CGPointMake(5, 0);//占位文字的起始位置;
@property(nonatomic,copy)void (^textHeightChangeBlock)(CGFloat height);
textView需要一個默認的初始行數(shù),默認是1,所以后續(xù)自定義的輸入框是要根據(jù)行數(shù)來確定高度,隨便給高度,動畫就很尷尬。
textView已經(jīng)屏蔽掉了iOS11 對textView作為UIScrollView子類的處理:
if (@available(iOS 11.0, *)) {
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
關(guān)于限制行數(shù)的處理:
-(void)textViewDidChange:(UITextView *)textView{
//內(nèi)容高度
CGFloat contentSizeH = self.textView.contentSize.height;
//最大高度
CGFloat maxHeight = ceil(self.font.lineHeight * self.maxLine);
//初始高度
CGFloat initiTextViewHeight = ceilf(self.initiLine *self.font.lineHeight);
if (contentSizeH <= maxHeight) {
if (contentSizeH <= initiTextViewHeight) {
self.textView.height = initiTextViewHeight;
}else{
self.textView.height = contentSizeH;
}
}else{
self.textView.height = maxHeight;
}
self.height = self.textView.height + 2 * self.v_margin;
if (self.textHeightChangeBlock) {
self.textHeightChangeBlock(self.height);
}
[textView scrollRangeToVisible:NSMakeRange(textView.selectedRange.location, 1)];
}
支持約束以及frame配置。
示例1 自定義一體鍵盤,限制最大行數(shù)。
很簡單的在xib底部關(guān)聯(lián)一個自定義的textView,需要監(jiān)測兩個通知UIKeyboardWillChangeFrameNotificatio,UIKeyboardDidChangeFrameNotification,至于為什么要監(jiān)聽,前面那篇文章有詳細說明。補充一點,如果項目中有使用到IQKeyboardManager,需要在當(dāng)前頁面設(shè)置IQKeyboardManager不可用,在自定義鍵盤的時候如果IQKeyboardManager開始,可能會出現(xiàn)導(dǎo)航欄突然消失很多問題,所以關(guān)閉掉,監(jiān)聽兩個通知即可,改變自定義鍵盤 底部距離屏幕底部的約束即可,鍵盤彈出,高于鍵盤即可。
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.isDisappear = NO;
[IQKeyboardManager sharedManager].enable = NO; //關(guān)閉
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
self.isDisappear = YES;
[IQKeyboardManager sharedManager].enable = YES; //開啟
}
-(void)keyboardWillChangeFrame:(NSNotification *)notification{
NSDictionary *userInfo = notification.userInfo;
// 動畫的持續(xù)時間
double duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 鍵盤的frame
CGRect keyboardF = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// NSLog(@"%@",NSStyringFromCGRect(keyboardF));
CGFloat keyboardY = keyboardF.origin.y;
keyboardH = keyboardF.size.height;
if (!self.isDisappear) {
[self dealKeyBoardWithKeyboardH:keyboardH keyboardY:keyboardY duration:duration];
}
}
-(void)keyboardDidChangeFrame:(NSNotification *)notification{
NSDictionary *userInfo = notification.userInfo;
// 動畫的持續(xù)時間
double duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardF = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardY = keyboardF.origin.y;
keyboardH = keyboardF.size.height;
if (self.isDisappear) {
[self dealKeyBoardWithKeyboardH:keyboardH keyboardY:keyboardY duration:duration];
}
}
#pragma mark---處理高度---
-(void)dealKeyBoardWithKeyboardH:(CGFloat)keyboardH keyboardY:(CGFloat)keyboardY duration:(CGFloat)duration{
if (!self.isDisappear) {
[UIView animateWithDuration:duration animations:^{
// 工具條的Y值 == 鍵盤的Y值 - 工具條的高度
if (keyboardY >= Device_Height) {
self.bottomH.constant = 0;
}else
{
self.bottomH.constant = keyboardH;
}
}];
}else{
if (keyboardY >= Device_Height) {
self.bottomH.constant = 0;
}else
{
self.bottomH.constant = keyboardH;
}
}
}
如果在鍵盤彈出的時候同時textView需要自動增長,那么也需要設(shè)置如下:
self.textView.textHeightChangeBlock = ^(CGFloat height) {
weakSelf.textH.constant = height;
weakSelf.bottomH.constant = keyboardH;
[weakSelf.view updateConstraints];
[weakSelf.view updateConstraintsIfNeeded];
[UIView animateWithDuration:0.25 animations:^{
[weakSelf.view layoutIfNeeded];
}];
};
示例2 cell跟隨textView自適應(yīng),textView也可以限制多行
需要做的也很簡單,在textView自動增長的地方,處理如下:(當(dāng)前textView不能失去焦點)
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
self.textView.initiLine = 1;
self.textView.maxLine = 3;
self.textView.placeholder= @"請輸入";
self.textViewH.constant = self.textView.height;
LXWS(weakSelf);
self.textView.textHeightChangeBlock = ^(CGFloat height) {
weakSelf.textViewH.constant = height;
[weakSelf.contentView updateConstraints];
[weakSelf.contentView updateConstraintsIfNeeded];
[UIView animateWithDuration:0.25 animations:^{
[weakSelf.contentView layoutIfNeeded];
}];
UITableView *tableView = [weakSelf tableView];
[tableView beginUpdates];
[tableView endUpdates];
};
補充
最近發(fā)現(xiàn)使用中發(fā)現(xiàn)示例2 結(jié)合IQKeyboardManager使用的時候出現(xiàn)的一點問題,在換行的時候輸入框的位置并沒有變化,只有當(dāng)鍵盤重新定位的時候才可以,如果能夠在換行的時候使鍵盤重新定位就好了。(2018年9月19日)
看一個IQKeyboardManager屬性:
/**
Refreshes textField/textView position if any external changes is explicitly made by user.
*/
- (void)reloadLayoutIfNeeded;
剛剛好可以在換行的時候重新進行鍵盤定位。
對于示例2 我們可以添加一行代碼:
self.textView.textHeightChangeBlock = ^(CGFloat height) {
weakSelf.textViewH.constant = height;
IQKeyboardManager *manager =[IQKeyboardManager sharedManager];
//當(dāng)輸入框位置變動時刷新位置
[manager reloadLayoutIfNeeded];
[weakSelf.contentView updateConstraints];
[weakSelf.contentView updateConstraintsIfNeeded];
[UIView animateWithDuration:0.25 animations:^{
[weakSelf.contentView layoutIfNeeded];
}];
UITableView *tableView = [weakSelf tableView];
[tableView beginUpdates];
[tableView endUpdates];
};
效果圖:
demo: LXCustomTextView