美文网首页MG的Swift空间MG的iOS经验总结iOS分享世界
简易总结封装一个带有占位文字的UITextField/TextV

简易总结封装一个带有占位文字的UITextField/TextV

作者: Mg明明就是你 | 来源:发表于2016-04-04 22:02 被阅读828次

    占位文字

    • 1、曾经有个这么一个项目需求: 使用textField时,占位文字默认是黑色的,我们的需求是当开始编辑时,让占位文字和光标变成红色(或其他颜色)
      • 思路: textField和button类似,内部都拥有子控件,在OC机制中,所有控件内部都是以懒加载的形式添加的.我们可以拿到textField中的子控件label,通过监听textField的状态,设置内部子控件label的样式.

    • 2、当系统自带的控件满足不了项目要求时
      • 对于 UITextField :

      1> 有占位文字 2> 最多只能输入一行文字

      • 对于UITextView

      1> 没有占位文字 2> 能输入任意行文字,并且超出显示范围的可以滚动(UITextView继承自UIScrollView)

      • 而我们需要的结果 :

    1> 有占位文字 2> 能输入任意行文字
    那么我们可以用脚想一想便可选择自定义控件继承于UITextField /UITextView,实现添加其占位文字的功能。


    • 3、以后开发中可能经常会使用到这种技术,所以我现在就总结一下如何弄占位文字以及修改占位文字的颜色,方便以后开发(只提供了一种思路,其他方法思路自己可以总结)。
      • 注意 : 以下方法我们最好是将它封装到一个分类中,提高代码的复用和封装性.

    以下是封装的代码:

    一、UITextField

    1.第一种方法:UITextField利用RunTime来设置占位文字的颜色

    主要思路: 方法二的主要思路是利用KVC思想,拿到TextFiled内部中的子控件,在使用KVC之前,用runtime变出TextFiled中所有子控件,找到placeholderLabel即可.

    ########################### .h文件 ###########################
    //  UITextField+LYMPlaceholderColor.m
    //  Created by ming on 14/12/20.
    //  Copyright © 2014年 ming. All rights reserved.
    
    #import <UIKit/UIKit.h>
    @interface UITextField (LYMPlaceholderColor)
    /** 占位颜色 */
    @property (nonatomic,strong) UIColor *placeholderColor;
    /** 名字 */
    @property (nonatomic,copy) NSString *name;
    @end
    
    ########################### .m文件 ###########################
    //  UITextField+LYMPlaceholderColor.m
    //  Created by ming on 14/12/20.
    //  Copyright © 2014年 ming. All rights reserved.
    /**
     *  利用RunTime来设置占位文字的颜色
     */
    
    
    #import "UITextField+LYMPlaceholderColor.h"
    // 导入头文件,导入下面其中一个即可
    #import <objc/runtime.h>
    //#import <objc/message.h>
    
    // OC最喜欢懒加载,用的的时候才会去加载
    // 需要给系统UITextField添加属性,只能使用runtime
    
    static NSString *const LYMPlaceholderLabelKey = @"placeholderLabel";
    static NSString *const placeholderColorName = @"placeholderColor";
    @implementation UITextField (LYMPlaceholderColor)
    
    #pragma mark - 利用RunTime动态增加属性和交换方法 =
    /// 实现交换方法 (mg_setPlaceholder:和setPlaceholder:的互换)
    + (void)load{
        Method mg_setPlaceholder = class_getInstanceMethod(self, @selector(mg_setPlaceholder:));
        
        Method setPlaceholder = class_getInstanceMethod(self, @selector(setPlaceholder:));
        
        method_exchangeImplementations(setPlaceholder, mg_setPlaceholder);
    }
    
    /// 外界赋值占位颜色的时候就会调用
    - (void)setPlaceholderColor:(UIColor *)placeholderColor{
        // 动态增加placeholderColor属性
        objc_setAssociatedObject(self, (__bridge const void *)(placeholderColorName), placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        // 设置颜色
       UILabel *placeholderLabel = [self valueForKeyPath:LYMPlaceholderLabelKey];
        placeholderLabel.textColor = placeholderColor;
    }
    - (UIColor *)placeholderColor{
        //    return  _placeholderColor;
        return objc_getAssociatedObject(self,(__bridge const void *)(placeholderColorName));
    }
    
    /// 外界赋值占位文字的时候会调用(自定义的方法,用来和系统的方法交换)
    - (void)mg_setPlaceholder:(NSString *)placeholder{
        // 1.设置占位文字
        [self mg_setPlaceholder:placeholder];
       
        // 2.设置占位文字颜色
        self.placeholderColor = self.placeholderColor;
    }
    
    
    #pragma mark - 测试RunTime动态增加属性
    - (void)setName:(NSString *)name{
        // 动态增加“name”属性
        objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    - (NSString *)name{
        return objc_getAssociatedObject(self, @"name");
    }
    
    @end
    

    总结:

    1, 文本框和按钮一样,都可以编辑文字,所以内部是有label的,所以需要拿到文本框中的label(可以在"小面包中检测"),当输入文字后,有个label就会消失,那个就是占位label,所以需要拿到系统内部的私有属性,但是不能直接拿到私有的属性和方法,所以需要用到KVC去取值和赋值.通过"运行时"拿到属性
    2, 然后通过KVC取值
    容易出错点: 不要用setValu:forKey,程序会崩掉,要用forKeyPath:表示不管你在文件的那一层都能去拿到


    2.第二种方法:UITextField 设置占位文字的颜色,让外界直接使用(这种方法有点投机取巧)

    --这样设置相对上一中方法来说就相对比较简洁

    ########################### .h文件 ###########################
    
    #import <UIKit/UIKit.h>
    
    @interface UITextField (placeholderColor)
    
    /** 占位颜色 */
    @property (nonatomic,strong) UIColor *placeholderColor;
    
    @end
    
    ########################### .m文件 ###########################
    /**
     *  设置占位文字的颜色,让外界直接使用
     */
    
    #import "UITextField+placeholderColor.h"
    
    static NSString *const placeholderColorKey = @"placeholderLabel.textColor";
    
    @implementation UITextField (placeholderColor)
    // 重写placeholderColor的setter方法
    - (void)setPlaceholderColor:(UIColor *)placeholderColor{
        // bool属性,有文字就这设置为YES
        BOOL change = NO;
        // 如果当前placeholder文字为空,那么就随便赋值几个文字,让它不为空
        if (self.placeholder == nil) {
            self.placeholder = @"mingge";
            // 设置 change = YES
            change = YES;
        }
        [self setValue:placeholderColor forKey:placeholderColorKey];
        // 如果change = YES,那么要把placeholder文字再次设为空
        if (change) {
            self.placeholder = nil;
        }
    }
    
    // 重写placeholderColor的getter方法
    - (UIColor *)placeholderColor{
        return [self valueForKeyPath:placeholderColorKey];
    }
    
    @end
    

    二、UITextView

    1.第一种方法:UITextView利用

    Quartz2D绘图 来设置占位文字以及颜色
    // 重绘
    [self setNeedsDisplay];

    ########################### .h文件 ###########################
    //  LYMTextView.h
    //  Created by ming on  14/12/9.
    //  Copyright © 2014年 ming. All rights reserved.
    
    #import <UIKit/UIKit.h>
    
    @interface LYMTextView : UITextView
    /** 占位文字 */
    @property (nonatomic,copy) NSString *placeholder;
    /** 文字颜色 */
    @property (nonatomic,strong) UIColor *placeholderColor;
    @end
    
    ########################### .m文件 ###########################
    /**
     *   给UITTextView显示占位文字的功能,以后如需使用,就可以直接拿去用
     */
    #import "LYMTextView.h"
    
    @implementation LYMTextView
    
    #pragma mark ========== 通知 =============
    - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]){
            self.textColor = [UIColor blackColor];
            
            // 设置占位文字的默认字体颜色和字体大小
            self.placeholderColor = [UIColor grayColor];
            self.font = [UIFont systemFontOfSize:15];
            
            // 发布通知(当空间的内容发生改变时)
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:self];
        }
        return self;
    }
    
    - (void)textDidChange:(NSNotification *)note{
        // 重绘
        [self setNeedsDisplay];
    }
    
    // 移除监听者
    - (void)dealloc{
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    #pragma mark ========== 绘制占位文字 ===========
    // 绘制占位文字
    - (void)drawRect:(CGRect)rect {
        // 如果有文字就不绘制(不执行下面的操作)
        if (self.text.length) return;
        
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    //    if (self.font) dict[NSFontAttributeName] = self.font;
    //    if (self.placeholderColor)  dict[NSForegroundColorAttributeName] = self.placeholderColor;
         dict[NSFontAttributeName] = self.font;
         dict[NSForegroundColorAttributeName] = self.placeholderColor;
    
        
        rect.origin.x = 4;
        rect.origin.y = 8;
        rect.size.width = LYMScreenWidth - 2 * rect.origin.x;
        
        [self.placeholder drawInRect:rect withAttributes:dict];
    }
    
    #pragma mark ========== 需要重写的属性 ===========
    // 重写占位文字
    - (void)setPlaceholder:(NSString *)placeholder{
        _placeholder = [placeholder copy];
        // 重绘
        [self setNeedsDisplay];
    }
    
    // 重写占位文字颜色
    - (void)setPlaceholderColor:(UIColor *)placeholderColor{
        _placeholderColor = placeholderColor;
        // 重绘
        [self setNeedsDisplay];
    }
    
    // 重写占位文字字体大小
    - (void)setFont:(UIFont *)font{
        [super setFont:font];
        // 重绘
        [self setNeedsDisplay];
    }
    
    // 重写文字
    - (void)setText:(NSString *)text{
        [super setText:text];
        // 重绘
        [self setNeedsDisplay];
    }
    
    // 重写文字属性
    - (void)setAttributedText:(NSAttributedString *)attributedText{
        [super setAttributedText:attributedText];
        // 重绘
        [self setNeedsDisplay];
    }
    
    // textView的尺寸发生改变
    - (void)layoutSubviews{
        [super layoutSubviews];
        // 重绘
        [self setNeedsDisplay];
    }
    
    @end
    

    2.第二种方法:UITextView利用

    刷新 来设置占位文字以及颜色
    // 重新布局
    [self setNeedsLayout];

    ########################### .h文件 ###########################
    //  LYMTextViewWithLabel.h
    //  Created by ming on 14/12/9.
    //  Copyright © 2014年 ming. All rights reserved.
    
    #import <UIKit/UIKit.h>
    
    @interface LYMTextViewWithLabel : UITextView
    /** 占位文字 */
    @property (nonatomic,copy) NSString *placeholder;
    /** 文字颜色 */
    @property (nonatomic,strong) UIColor *placeholderColor;
    @end
    
    ########################### .m文件 ###########################
    #import "LYMTextViewWithLabel.h"
    
    @interface LYMTextViewWithLabel ()
    /** 占位Label */
    @property (nonatomic,weak)  UILabel *placeholderLabel;
    @end
    
    @implementation LYMTextViewWithLabel
    
    #pragma mark ========== 通知 =============
    - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]){
            // 创建一个UILabel
            UILabel *placeholderLabel = [[UILabel alloc] init];
            placeholderLabel.numberOfLines = 0;
            [self addSubview:placeholderLabel];
            self.placeholderLabel = placeholderLabel;
            
            // 设置占位文字的默认字体颜色和字体大小
            self.textColor = [UIColor blackColor];
            self.font = [UIFont systemFontOfSize:15];
            
            // 发布通知(当空间的内容发生改变时)
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:self];
        }
        return self;
    }
    
    // 布局占位文字的位置和尺寸
    - (void)layoutSubviews{
        [super layoutSubviews];
        self.placeholderLabel.x = 4;
        self.placeholderLabel.y = 8;
        self.placeholderLabel.width = self.width - 2*self.placeholderLabel.x;
        // 自适应
        [self.placeholderLabel sizeToFit];
    }
    
    - (void)textDidChange:(NSNotification *)note{
        // 是否隐藏
        self.placeholderLabel.hidden = self.hasText;
    }
    
    // 移除监听者
    - (void)dealloc{
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    
    - (void)setPlaceholderColor:(UIColor *)placeholderColor{
        self.placeholderLabel.textColor = placeholderColor;
    }
    
    #pragma mark ========== 重新计算placeholderLabel的尺寸 =============
    - (void)setFont:(UIFont *)font{
        [super setFont:font];
        self.placeholderLabel.font = self.font;
        // 重新布局
        [self setNeedsLayout];
    }
    
    - (void)setPlaceholder:(NSString *)placeholder{
        self.placeholderLabel.text = [placeholder copy];
        // 重新布局
        [self setNeedsLayout];
    }
    
    #pragma mark ========== 隐藏placeholderLabel =============
    - (void)setText:(NSString *)text{
        [super setText:text];
        // 根据是否有文字来判断要不要隐藏
        self.placeholderLabel.hidden = self.hasText;
    }
    
    - (void)setAttributedText:(NSAttributedString *)attributedText{
        [super setAttributedText:attributedText];
        // 根据是否有文字来判断要不要隐藏
        self.placeholderLabel.hidden = self.hasText;
    }
    
    @end
    

    3.runTime

    • 头文件
    #import <objc/runtime.h>
    #import <objc/message.h>```
    
    - viewDidLoad
    
    
    • (void)viewDidLoad {
      [super viewDidLoad];  
      // 通过运行时,发现UITextView有一个叫做“_placeHolderLabel”的私有变量
      unsigned int count = 0;
      Ivar *ivars = class_copyIvarList([UITextView class], &count);
      for (int i = 0; i < count; i++) {
      Ivar ivar = ivars[i];
      const char *name = ivar_getName(ivar);
      NSString *objcName = [NSString stringWithUTF8String:name];
      NSLog(@"%d : %@",i,objcName);
      }
      [self setupTextView];
      }```

    • setupTextView

    - (void)setupTextView{
            // 提示文字
            CGFloat margin  = 15;
            
            UILabel *tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(margin, 0, MGSCREEN_width - 2 * margin, 50)];
            tipLabel.text = @"你的批评和建议能帮助我们更好的完善产品,请留下你的宝贵意见!";
            tipLabel.numberOfLines = 2;
            tipLabel.textColor = MGRGBColor(255, 10, 10);
            tipLabel.font = MGFont(16);
            [self.view addSubview:tipLabel];
            // 意见输入框
            CGFloat height  = 200;
    #ifndef __IPHONE_4_0
            height = 100;
    #endif
            UITextView *iderTextView = [[UITextView alloc] initWithFrame:CGRectMake(margin, CGRectGetMaxY(tipLabel.frame) + margin, MGSCREEN_width - 2 * margin, height)];
            iderTextView.backgroundColor = [UIColor whiteColor];
            iderTextView.scrollEnabled = YES;
            iderTextView.scrollsToTop = YES;
            iderTextView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
    //    iderTextView.delegate = self;
            self.iderTextView = iderTextView;
            [self.view addSubview:iderTextView];
        
            // _placeholderLabel
            UILabel *placeHolderLabel = [[UILabel alloc] init];
            placeHolderLabel.text = @"请输入宝贵意见(300字以内)";
            placeHolderLabel.numberOfLines = 0;
            placeHolderLabel.font = [UIFont systemFontOfSize:14];
            placeHolderLabel.textColor = [UIColor lightGrayColor];
            [placeHolderLabel sizeToFit];
            [iderTextView addSubview:placeHolderLabel];
        
            [iderTextView setValue:placeHolderLabel forKey:@"_placeholderLabel"];
            iderTextView.font =  placeHolderLabel.font;
    }
    

    补充:一种最简单的实现占位文字的textView(该方法有点投机取巧)

    • viewDidLoad
    - (void)viewDidLoad {
        [super viewDidLoad];
        //    意见输入
        myTextView=[[UITextView alloc] initWithFrame:(CGRectMake(10, 33, kScreenWidth-20, 130))];
        myTextView.font=kFont(15);
        myTextView.delegate=self;
        myTextView.backgroundColor=self.view.backgroundColor;
        ViewBorderRadius(myTextView, 0, 0.5f, kGray);
        myTextView.textColor=kGray;
        myTextView.text=@" 请输入详细描述";
        myTextView.tintColor=kWhite;
        [self.view addSubview:myTextView];
        //    提交
        UIButton *feedBtn=[UIButton buttonWithType:(UIButtonTypeCustom)];
        feedBtn.frame=CGRectMake(100, myTextView.tail+40, kScreenWidth-200, 40);
        [feedBtn addTarget:self action:@selector(feedBtnHandled:) forControlEvents:(UIControlEventTouchUpInside)];
        [feedBtn setTitle:@"提交" forState:(UIControlStateNormal)];
        [feedBtn setTitleColor:[UIColor whiteColor] forState:(UIControlStateNormal)];
        feedBtn.titleLabel.font=kFont(18);
        feedBtn.backgroundColor=naBarTiniColor;
        [self.view addSubview:feedBtn];
    
    }```
    
    - UITextViewDelegate
    
    
    • (void)textViewDidBeginEditing:(UITextView *)textView{
      if([textView.text isEqualToString:@" 请输入详细描述"]){
      textView.text=@"";
      textView.textColor=kWhite;
      }
      }

    • (void)textViewDidEndEditing:(UITextView *)textView{

      if([textView.text isEmptyString]){

        textView.text=@" 请输入详细描述";
        textView.textColor=kGray;
      

      }
      }

    ![未输入时](http:https://img.haomeiwen.com/i1429890/73a3f245a9ced10a.PNG)
    ![UITextView成为第一响应者时](http:https://img.haomeiwen.com/i1429890/10b06997fb7af974.PNG)
    ***

    相关文章

      网友评论

      本文标题:简易总结封装一个带有占位文字的UITextField/TextV

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