iOS 自定義一個textView,可做聊天輸入框,cell中也可以自適應(yīng)

前言

項目中經(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)屏蔽掉了iOS11textView作為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];
      
    };

效果圖:
textView.gif

demo: LXCustomTextView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容