iOS 仿即刻評論輸入框帶圖片

weixin_34337265發表於2018-03-02
效果圖
662079-0bd71dd500d56586.gif
效果圖.gif
功能點
  1. 輸入框自適應高度
  2. 達到某個高度高度不再變化
  3. 底部顯示圖片
  4. 鍵盤的彈起和收起適應
用到的控制元件
  • UITextView
  • UIImageView
  • UIScrollView
  • UIButton
  • UIView
思路

UIScrollViewcontentSizeUITextView 的文字高度 + UIImageView 的高度
UIScrollView 的最大高度為 UITextView 顯示最多行數的文字高度,加上圖片的高度

具體步驟
  • 建立 CommentView 進行封裝好,CommentView 需要實現的功能為 UI 介面的搭建、鍵盤彈起和收起的適應,選擇圖片之後對介面約束的一些更新操作

  • commentView.h需要的一些屬性

@property (nonatomic, weak) UIViewController *contoller; /**< 將控制器傳入,跳轉相簿 */
@property (nonatomic, weak) MASConstraint *bottomConstraint; /**< CommentView 的底部約束,鍵盤彈起和收起時更新約束 */
  • commentView.m 屬性
@property (nonatomic, strong) UIScrollView *contentScrollView; /**< 評論內容 */
@property (nonatomic, strong) UIView *contentView; /**< 內容檢視 */
@property (nonatomic, strong) UIImageView *imageView; /**< 圖片 */
@property (nonatomic, strong) GPTextView *textView; /**< 輸入框 */
@property (nonatomic, strong) UIButton *chooseImageButton; /**< 選擇圖片按鈕 */

@property (nonatomic, assign) CGFloat imageHeight; /**< 圖片高度 */
@property (nonatomic, assign) CGFloat commentHeight; /**< 評論框的高度 */
  • GPTextView 是自定義的一個類,繼承於 UITextView , GPTextView.h 檔案
typedef void (^ChangeTextHeight)(NSString *text, CGFloat height, BOOL autoChangeHeight); /**< 改變輸入框高度回撥 */

@interface GPTextView : UITextView

#pragma mark - Property

@property (nonatomic, copy) NSString *placeholder; /**< 佔位文字 */
@property (nonatomic, strong) UIColor *placeholderColor; /**< 佔位文字顏色 */
@property (nonatomic, strong) UIFont *placeholderFont; /**< 佔位文字字型大小 */
@property (nonatomic, assign) NSInteger numberOfLines; /**< 行數 0-無限行 */


#pragma mark - Method

/**
 改變輸入框的高度
 */
- (void)textHeightDidChange:(ChangeTextHeight)changeText;

@end
  • GPTextView.m 屬性
@property (nonatomic, assign) CGFloat textHeight; /**< 文字高度 */
@property (nonatomic, assign) CGFloat maxTextHeight; /**< 文字最大高度 */
@property (nonatomic, strong) UILabel *placeholderLabel; /**< 佔位文字 */

@property (nonatomic, assign) BOOL autoChangeHeight; /**< 是否需要自動改變高度 */
@property (nonatomic, copy) ChangeTextHeight changeTextHeightBlock;

其中對 GPTextViewplaceholder 實現這裡就不描述了,主要是描述一下輸入框的自適應高,首先註冊 UITextViewTextDidChangeNotification 通知,監聽 textView 輸入文字的改變;然後在監聽方法裡面進行判斷是否需要改變 textView 的高度

- (void)textDidChange {
    
    self.placeholderLabel.hidden = self.text.length > 0 ? YES : NO; // 佔位文字的隱藏和顯示
    
    NSInteger height = ceilf([self sizeThatFits:CGSizeMake(self.bounds.size.width, MAXFLOAT)].height); // 計算出當前文字高度
    
    if (self.textHeight != height) { // 高度不一樣,行數改變了
        
        // 是否需要改變 CommentView 的高度
        self.autoChangeHeight = height <= self.maxTextHeight && self.maxTextHeight > 0;
        self.textHeight = height;
        
        if (self.changeTextHeightBlock) {
            self.changeTextHeightBlock(self.text, self.textHeight, self.autoChangeHeight);
        }
    }
}

GPTextView 中主要操作就是這些,下面回到 commentView.m

  • 對鍵盤的彈起和收起進行監聽
- (void)addObserver {
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardChange:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardChange:) name:UIKeyboardWillHideNotification object:nil];
}

監聽方法實現

- (void)keyboardChange:(NSNotification *)notifi {
    
    NSDictionary *userInfo = notifi.userInfo;
    CGFloat duration = [[userInfo valueForKeyPath:@"UIKeyboardAnimationDurationUserInfoKey"] floatValue];
    CGFloat keyboardHeight = [[userInfo valueForKeyPath:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue].size.height;  /**< 鍵盤的高度 */
    if ([notifi.name isEqualToString:UIKeyboardWillShowNotification]) {
        // 鍵盤彈起
        [self updateBottomConstraintsWithHeight:keyboardHeight duration:duration];
        
    } else if ([notifi.name isEqualToString:UIKeyboardWillHideNotification]) {
        // 鍵盤收起
        [self updateBottomConstraintsWithHeight:0 duration:duration];
    }
}

/**
 更新底部約束
 */
- (void)updateBottomConstraintsWithHeight:(CGFloat)height duration:(CGFloat)duration {
    
    self.bottomConstraint.offset(-height);
    [UIView animateWithDuration:duration animations:^{
        [self.superview layoutIfNeeded];
    }];
}

其中 bottomConstraint 是在新增 commentView 時,設定的底部約束的時候賦值好,這個屬性在 commentView.h

// 輸入框
[self.commentView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.right.equalTo(self.view);
    self.commentView.bottomConstraint = make.bottom.equalTo(self.view).offset(0);
    make.height.mas_equalTo(30);
}];

這樣,鍵盤彈起和收起適配,就不用在外面去控制了

  • 輸入文字,高度改變,實現 textHeightDidChange 這個方法
[_textView textHeightDidChange:^(NSString *text, CGFloat height, BOOL autoChangeHeight) {
    [wkSelf updateHeightWithHeight:height autoChangeHeight:autoChangeHeight];
}];

updateHeightWithHeight:autoChangeHeight 方法實現

- (void)updateHeightWithHeight:(CGFloat)height autoChangeHeight:(BOOL)autoChangeHeight {
    
    CGFloat imageHeight = self.imageView.image ? self.imageHeight : 0;
    if (autoChangeHeight) {
        // 設定輸入框的高度
        [self mas_updateConstraints:^(MASConstraintMaker *make) {
            make.height.mas_equalTo(height + imageHeight);
        }];
    }
    // 設定文字可滾動範圍
    [self.contentView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.height.mas_equalTo(height + imageHeight);
    }];
    [self.textView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.height.mas_equalTo(height);
    }];
    [self layoutIfNeeded];
}

autoChangeHeightYES 時,才對 commentView 的高度進行改變,否則只更新 textView 的高度和 scrollViewcontentSize 屬性。

  • 選擇圖片的時候,如果是第一次選擇圖片 commentView 的高度就需要改變,在 imagePickerController:didFinishPickingMediaWithInfo 中進行操作
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    UIImage *image = [info valueForKeyPath:@"UIImagePickerControllerOriginalImage"];
    BOOL autoChangeHeight = self.imageView.image ? NO : YES; //  是否需要改變高度 第一次選擇圖片 YES 切換圖片 NO
    self.imageView.image = image;
    [self layoutIfNeeded];
    
    if (autoChangeHeight) {
        [self.imageView mas_updateConstraints:^(MASConstraintMaker *make) {
            make.height.mas_equalTo(self.imageHeight);
        }];
        BOOL isMoreThree = CGRectGetHeight(self.textView.frame) > CGRectGetHeight(self.contentScrollView.frame);
        if (isMoreThree) {
            // 設定輸入框的高度
            [self mas_updateConstraints:^(MASConstraintMaker *make) {
                make.height.mas_equalTo(CGRectGetHeight(self.contentScrollView.frame) + self.imageHeight);
            }];
            // 設定文字可滾動範圍
            [self.contentView mas_updateConstraints:^(MASConstraintMaker *make) {
                make.height.mas_equalTo(CGRectGetHeight(self.textView.frame) + self.imageHeight);
            }];
            [self.contentScrollView setContentOffset:CGPointMake(0, self.contentScrollView.contentSize.height - CGRectGetHeight(self.contentScrollView.frame)) animated:YES];
        } else {
            [self updateHeightWithHeight:self.textView.frame.size.height autoChangeHeight:autoChangeHeight];
        }
    }
    [self layoutIfNeeded];
    [picker dismissViewControllerAnimated:YES completion:nil];
}

以上就是仿照即刻 App 輸入框的一個實現

程式碼

相關文章