iOS 仿即刻评论输入框带图片

效果图
iOS 仿即刻评论输入框带图片_第1张图片
效果图.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 *)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 输入框的一个实现

代码

你可能感兴趣的:(iOS 仿即刻评论输入框带图片)