美文网首页开发iOS DeveloperiOS && Android
支持自动布局,自动高度变化和palceholder的输入框

支持自动布局,自动高度变化和palceholder的输入框

作者: KevinTing | 来源:发表于2016-02-25 22:40 被阅读673次

    这是效果,输入框根据内容多少自动伸缩大小。

    输入框.gif
    关于输入框遮挡键盘的处理在另外一篇文章描述。

    1、继承UITextView

    UITextField只能输入一行,要输入多行文本,那么只能用UITextView,如下所示,KTAutoHeightTextView继承自UITextView,然后使用自动布局添加三个高度上的约束,并连线:


    Paste_Image.png

    这里heightConstraint是用来控制实际textView的高度的,maxHeightConstraint和minHeightConstraint则分别用来控制最大和最小的高度。

    2、IB_DESIGNABLE和IBInspectable的实时预览

    除此之外,还定义了2个属性showsRoundCorner和placeholder,注意到开头有个IB_DESIGNABLE,这两个属性前面的还多出来了IBInspectable,IB_DESIGNABLE配合IBInspectable的作用就是在storyboard或者xib中实时更新属性效果的。有了这两个东西,会发现KTAutoHeightTextView的属性检查器中会多出两个属性:


    Paste_Image.png

    仅仅用IB_DESIGNABLE和IBInspectable还不足以达到实时在storyboard或者xib中预览圆角和placeholder的效果,还要在相应的属性setter中加上更新的代码,比如showsRoundCorner属性的setter:

    - (void)setShowsRoundCorner:(BOOL)showsRoundCorner
    {
        _showsRoundCorner = showsRoundCorner;
        if (showsRoundCorner)
        {
            self.layer.masksToBounds = YES;
            self.layer.cornerRadius = 5.0;
            self.layer.borderColor = [[UIColor lightGrayColor] CGColor];
            self.layer.borderWidth = 0.5;
        }
        else
        {
            self.layer.masksToBounds = NO;
            self.layer.cornerRadius = 0.0;
            self.layer.borderColor = [[UIColor clearColor] CGColor];
            self.layer.borderWidth = 0.0;
        }
    }
    

    在storyboard中设置“Shows RoundCorner”为On,那么就会看到预览的圆角效果了:


    Paste_Image.png

    3、placeholder实现

    同样实现placeholder的setter:

    - (void)setPlaceholder:(NSString *)placeholder
    {
        _placeholder = [placeholder copy];
        [self setNeedsDisplay];
    }
    
    #pragma mark - Drawing
    
    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
        
        if ([self.text length] == 0 && self.placeholder) {
            [[UIColor lightGrayColor] set];
            [self.placeholder drawInRect:CGRectInset(rect, 6.0f, 8.0f) withAttributes:[self kt_placeholderTextAttributes]];
        }
    }
    
    #pragma mark - Utilities
    
    - (NSDictionary *)kt_placeholderTextAttributes
    {
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
        paragraphStyle.alignment = self.textAlignment;
        
        return @{ NSFontAttributeName : self.font,
                  NSForegroundColorAttributeName : [UIColor lightGrayColor],
                  NSParagraphStyleAttributeName : paragraphStyle };
    }
    

    这里在setter里面调用setNeedsDisplay方法,该方法调用之后,drawRect方法会被调用,然后在这里面加上绘制placeholder文本的逻辑。

    4、自动高度变化的实现

    这里的实现思路是监听文本编辑,文本变化的通知,然后调用setNeedsDisplay,注意setNeedsDisplay不光会导致drawRect方法被触发,还会导致layoutSubviews方法被触发来进行重布局,因此在layoutSubviews方法里面写上更新高度的逻辑,代码很简单:

    - (void)awakeFromNib
    {
        [super awakeFromNib];
        
        [self addTextViewNotificationObservers];
    }
    
    - (void)dealloc
    {
        [self removeTextViewNotificationObservers];
    }
    
    - (void)layoutSubviews
    {
        [super layoutSubviews];
        
        // calculate size needed for the text to be visible without scrolling
        CGSize sizeThatFits = [self sizeThatFits:self.frame.size];
        float newHeight = sizeThatFits.height;
        // if there is any minimal height constraint set, make sure we consider that
        if (self.maxHeightConstraint) {
            newHeight = MIN(newHeight, self.maxHeightConstraint.constant);
        }
        // if there is any maximal height constraint set, make sure we consider that
        if (self.minHeightConstraint) {
            newHeight = MAX(newHeight, self.minHeightConstraint.constant);
        }
        // update the height constraint
        self.heightConstraint.constant = newHeight;
    }
    
    #pragma mark -- notifications
    
    - (void)addTextViewNotificationObservers
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(kt_didReceiveTextViewNotification:)
                                                     name:UITextViewTextDidChangeNotification
                                                   object:self];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(kt_didReceiveTextViewNotification:)
                                                     name:UITextViewTextDidBeginEditingNotification
                                                   object:self];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(kt_didReceiveTextViewNotification:)
                                                     name:UITextViewTextDidEndEditingNotification
                                                   object:self];
    }
    
    - (void)removeTextViewNotificationObservers
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:UITextViewTextDidChangeNotification
                                                      object:self];
        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:UITextViewTextDidBeginEditingNotification
                                                      object:self];
        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:UITextViewTextDidEndEditingNotification
                                                      object:self];
    }
    
    - (void)kt_didReceiveTextViewNotification:(NSNotification *)notification
    {
        [self setNeedsDisplay];
    }
    

    代码是在利用sizeThatFits在contentSize变化的时候去计算合适的大小fitHeight,同时利用一定的规则在合适的时候寻找高度约束heightConstraint。当存在heightConstraint的时候修改约束值,不存在的时候直接修改bounds,从而实现在自动布局或者非自动布局情况下都能自动匹配高度。

    5、重写属性的setter

    重写属性的setter,保证实时更新。注意setBounds的setter,是为了避免出现错误contentOffset的情况。

    #pragma mark -- 重写系统的setter --
    
    - (void)setBounds:(CGRect)bounds
    {
        [super setBounds:bounds];
        
        if (self.contentSize.height <= self.bounds.size.height + 1){
            self.contentOffset = CGPointZero; // Fix wrong contentOffset
        }
    }
    
    - (void)setText:(NSString *)text
    {
        [super setText:text];
        [self setNeedsDisplay];
    }
    
    - (void)setAttributedText:(NSAttributedString *)attributedText
    {
        [super setAttributedText:attributedText];
        [self setNeedsDisplay];
    }
    
    - (void)setFont:(UIFont *)font
    {
        [super setFont:font];
        [self setNeedsDisplay];
    }
    
    - (void)setTextAlignment:(NSTextAlignment)textAlignment
    {
        [super setTextAlignment:textAlignment];
        [self setNeedsDisplay];
    }
    

    完整的项目https://github.com/tujinqiu/KTAutoHeightTextView

    相关文章

      网友评论

        本文标题:支持自动布局,自动高度变化和palceholder的输入框

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