美文网首页ios实用开发技巧小知识点iOS Developer
iOS 自定义工具类 ---- 自适应输入框

iOS 自定义工具类 ---- 自适应输入框

作者: 小白进城 | 来源:发表于2017-09-19 10:26 被阅读490次

    效果图

    效果图

    关键方法

    - (CGSize)sizeThatFits:(CGSize)size;
    

    思路

    1、使用sizeThatFits方法获取UITextView的实时高度
    2、监听键盘的出现和消失事件,改变输入框的y,调整输入框的位置
    3、- (void)textViewDidChange:(UITextView *)textView 方法中获取输入内容
    4、通过代理模式,将数据传递给指定对象
    5、代理方法中使用Block作为参数,带回处理结果,如消息发送成功
    6、添加透明的背景视图用于收起键盘


    方法实现关键点

    1、sizeThatFits

    CGSize size = [textView sizeThatFits:CGSizeMake(textView.frame.size.width, MAXFLOAT)];
    NSLog(@"textView高度:%f",size.height);
    

    2、监听键盘

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    
    

    事件处理

    // !!!: 键盘显示
    -(void)keyboardWillShow:(NSNotification*)notification{
        NSDictionary *dic =notification.userInfo;
        // 获取键盘的frame
        NSNumber *keyboardFrame= dic[@"UIKeyboardFrameEndUserInfoKey"];
        CGRect keyboardFrameNew = keyboardFrame.CGRectValue;
        // 动画时间
        float animationTime =   [dic[@"UIKeyboardAnimationDurationUserInfoKey"]floatValue];
        // 动画速度
        int animationCurve =[dic[@"UIKeyboardAnimationCurveUserInfoKey"]intValue];
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:animationTime];
        [UIView setAnimationCurve:animationCurve];
        // 控件位置、样式设置
        // do something
        [UIView commitAnimations];
    }
    // !!!: 键盘隐藏
    -(void)keyboardWillHide:(NSNotification*)notification{
        NSDictionary *dic = notification.userInfo;
        // 获取动画时间
        float animationTime = [dic[@"UIKeyboardAnimationDurationUserInfoKey"]floatValue];
        // 获取动画的速度
        int animationCurve =[dic[@"UIKeyboardAnimationCurveUserInfoKey"]intValue];
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:animationTime];
        [UIView setAnimationCurve:animationCurve];
        // 控件位置、样式设置
        // do something
        [UIView commitAnimations];
    }
    

    3、获取输入内容

    -(void)textViewDidChange:(UITextView *)textView{
        self.content = textView.text;   // 输入的内容
    }
    

    4、代理传递数据

    其中的block带回消息处理结果

    @optional
    -(void)commentView:(CommentView*)commentView sendMessage:(NSString*)message complete:(void(^)(BOOL success))completeBlock;
    

    5、收起键盘

    收起键盘的视图因为超过父视图,正常是不会响应点击事件的,我们通过修改以下方法的返回值改变响应链

    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

    // !!!: 超过父视图的子视图可以点击
    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
        NSArray *subViews = self.subviews;
        if ([subViews count] > 1)
        {
            for (UIView *aSubView in subViews)
            {
                if ([aSubView pointInside:[self convertPoint:point toView:aSubView] withEvent:event])
                {
                    return YES;
                }
            }
        }
        if (point.x > 0 && point.x < self.frame.size.width && point.y > 0 && point.y < self.frame.size.height)
        {
            return YES;
        }
        return NO;
    }
    

    使用方法

    上面简单介绍了实现过程,下面来看下如何使用

    1、声明一个输入框视图,并实现代理

    @interface ViewController ()<CommentViewDelegate>
    @property (strong ,nonatomic) CommentView *commentTool;
    @end
    

    2、懒加载方式初始化该视图

    -(CommentView *)commentTool{
        if (_commentTool==nil) {
            NSArray *itemArray = [[NSBundle mainBundle] loadNibNamed:@"CommentView" owner:nil options:nil];
            for (id item in itemArray) {
                if ([item isMemberOfClass:[CommentView class]]) {
                    _commentTool = item;
                    _commentTool.y = kScreenHeight - _commentTool.viewHeight;
                    _commentTool.delegate = self;
                }
            }
        }
        return _commentTool;
    }
    

    3、实现其代理方法

    // !!!: 评论的代理
    -(void)commentView:(CommentView *)commentView sendMessage:(NSString *)message complete:(void (^)(BOOL))completeBlock{
        DLog(@"评论:%@",message);
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.label.text = message;
            // 收起键盘
            completeBlock(YES); // 发送成功时
    //        completeBlock(NO); // 发送失败时
        });
    }
    

    Demo地址

    demo传送门


    总结

    1、在输入内容时,因为size的变化,需要重新调整控件的frame;在收回控件时如果需要回复到最初状态,需要记录最初的状态,当父视图addsubview时会触发子视图-(void)willMoveToSuperview:(UIView *)newSuperview事件,这里可以得到父视图,并且记录控件的最初状态、位置等信息

    2、我们知道,有返回值的代理方法使用的在主线程中,显然这种方式并不适合在:B将事件传递给A,并希望A在某一不确定时刻再将事件传递回来,这样的情况里,所以我使用Block传递这不确定时刻的消息,你也可以使用通知、子控件传递过来等方式实现相同效果,不过个人觉得block会更简洁

    3、这个自适应输入框存在Bug:如果页面有滑动返回手势时,键盘的将要消失出现事件下改变控件的width时,会出现子控件的frame错误,不知道时系统本身问题还是什么,解决方案有两个:1、取消滑动返回手势 2、控件本身不改变最初的width,只做整体控件y的更改

    4、针对3的问题,如果读者有更好的解决方案,希望留言回复,谢谢

    相关文章

      网友评论

        本文标题:iOS 自定义工具类 ---- 自适应输入框

        本文链接:https://www.haomeiwen.com/subject/lxhwsxtx.html