iOS开发——真·高度自适应的TextField

作者: Lol刀妹 | 来源:发表于2016-08-23 10:41 被阅读2637次
    Apink-朴初珑

    产品需求:

    由于单行的输入栏无法展示完整的用户地址,现要求在原有功能的基础上进行改进:地址栏文本超过一行时,多行显示。

    思路:

    原来的地址输入栏就是个TextField,由于TextField只能展示一行,故必须换控件。原本的功能必须保证,故这个控件可以总结为:高度随文本内容增减而改变并且带placeholder的特殊TextField。具有输入功能的特殊TextField,当然TextView。

    自定义控件:

    主要步骤如下

    • 新建一个继承自UIView的控件CQTextView
    • CQTextView上放一个UITextView作为输入控件
    • 再在CQTextView上放一个UILabel作为显示placeholder的控件
    • 输入控件随文本内容多少而改变高度
    • 输入控件文本内容为空时展示placeholder的控件

    代码说明

    • .h文件
    #import <UIKit/UIKit.h>
    
    @interface CQTextView : UIView
    
    @property (nonatomic,copy) NSString *placeholder;
    @property (nonatomic,strong) UIFont *font;
    
    @end
    
    
    • .m文件
    #import "CQTextView.h"
    
    @interface CQTextView (){
        /** 记录初始化时的height,textview */
        CGFloat _initHeight;
    }
    
    @property (nonatomic,strong) UITextView *textView;
    /** placeholder的label */
    @property (nonatomic,strong) UILabel *placeholderLabel;
    
    @end
    
    @implementation CQTextView
    
    /** 重写初始化方法 */
    - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]) {
            // 记录初始高度
            _initHeight = frame.size.height;
            self.clipsToBounds = NO;
            
            // 添加textView
            self.textView = [[UITextView alloc]initWithFrame:self.bounds];
            [self addSubview:self.textView];
            self.textView.delegate = (id)self;
            self.textView.backgroundColor = [UIColor clearColor];
            
            // 添加placeholderLabel
            self.placeholderLabel = [[UILabel alloc]initWithFrame:CGRectMake(3, 0, frame.size.width - 3, frame.size.height)];
            [self addSubview:self.placeholderLabel];
            self.placeholderLabel.backgroundColor = [UIColor clearColor];
            self.placeholderLabel.textColor = [UIColor lightGrayColor];
        }
        return self;
    }
    
    // 赋值placeholder
    - (void)setPlaceholder:(NSString *)placeholder{
        _placeholder = placeholder;
        self.placeholderLabel.text = placeholder;
        [self.placeholderLabel sizeToFit];
        self.placeholderLabel.center = self.textView.center;
    }
    
    // 赋值font
    - (void)setFont:(UIFont *)font{
        self.textView.font = self.placeholderLabel.font = font;
        // 重新调整placeholderLabel的大小
        [self.placeholderLabel sizeToFit];
        self.placeholderLabel.center = self.textView.center;
    }
    
    /** textView文本内容改变时回调 */
    - (void)textViewDidChange:(UITextView *)textView{
        // 计算高度
        CGSize size = CGSizeMake(self.textView.frame.size.width, CGFLOAT_MAX);
        NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:self.textView.font,NSFontAttributeName, nil];
        CGFloat curheight = [textView.text boundingRectWithSize:size
                                                        options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                                     attributes:dic
                                                        context:nil].size.height;
        // 如果高度小于初始化时的高度,则不赋值(仍采用最初的高度)
        if (curheight < _initHeight) {
            self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, _initHeight);
            self.textView.frame = CGRectMake(self.textView.frame.origin.x, self.textView.frame.origin.y, self.textView.frame.size.width, _initHeight);
        }else{
            // 重新给frame赋值(改变高度)
            self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, curheight+20);
            self.textView.frame = CGRectMake(self.textView.frame.origin.x, self.textView.frame.origin.y, self.textView.frame.size.width, curheight+20);
        }
        
        // 如果文本为空,显示placeholder
        if (textView.text.length == 0) {
            self.placeholderLabel.hidden = NO;
            self.placeholderLabel.center = self.textView.center;
        }else{
            self.placeholderLabel.hidden = YES;
        }
    }
    
    @end
    
    • 使用
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        CQTextView *textView = [[CQTextView alloc]initWithFrame:CGRectMake(90, 90, 100, 30)];
        [self.view addSubview:textView];
        textView.backgroundColor = [UIColor redColor];
        textView.font = [UIFont systemFontOfSize:20];
        textView.placeholder = @"ss";
    }
    

    效果图

    效果图.gif

    后记:

    建议大家都掌握这种控件的封装方法,因为在实际项目中的使用还是挺频繁的,比如我们常用的微信,它的输入框就类似于这种。
    注:评论里的buttonTouch大神提供了一种完美解决换行时未及时更新高度的方法,大家一定要看!

    相关文章

      网友评论

      • 我叫赵小贱:placeholder可以用运行时加给TextView上,效果和Label的一样。
      • 十一岁的加重:话说一楼去哪里了
        Lol刀妹:@十一岁的加重 一楼是楼主:joy:
      • 88c862862018: :+1:
        Lol刀妹:@广羽人三_ 2楼那位才是大神:grin:
      • 独木舟的木:新手问个题外话,请问效果图是用的什么录屏工具咧?
        Lol刀妹:@独木舟的木 用的licecap 你可以看下这篇文章http://www.jianshu.com/p/1cdbe37b5804
      • aaa000:你有没有发现 每次换行的时候很不自然,当第一行写完了 第二行写了一个字 的时候感觉那不太对,然后写下第二行第二个字的时候 就很明显的发现了问题。 微信的输入框 不仅做了自动换行还做了 输入特殊字符串(手机号码 银行卡号 网址 等)在一个行的末尾不够展示时自动换行等等操作!相当复杂(什么图文混排 表情有些显示为 特殊指定字符串 有些显示为 图片)
        Lol刀妹:@buttonTouch 换行时的那个bug 你是怎样解决的?
        aaa000:@无夜之星辰 我没有他们的源码,前几天做一个类似微信聊天的app(主要是想学一下即时通讯) 然后研究了一下 微信的键盘!刚好遇到你写这个东西,我也写过 所以就感慨了一下!
        Lol刀妹:@buttonTouch 确实,多谢指出。下来我会花时间慢慢优化的。不过....我估计你应该有类似于微信输入框那种效果的代码,那么现在问题来了——能否分享? :yum:

      本文标题:iOS开发——真·高度自适应的TextField

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