美文网首页iOS日常知识储备UITextFieldiOS开发实用技术
关于设置TextFiled中占位文字的颜色的几个方法

关于设置TextFiled中占位文字的颜色的几个方法

作者: Alexander | 来源:发表于2016-02-28 23:01 被阅读1357次

    欢迎"@WilliamAlex大叔"一起讨论iOS技术

    项目需求: 使用textField时,占位文字默认是黑色的,我们的需求是当开始编辑时,让占位文字和光标变成红色(或其他颜色)

    思路: textField和button类似,内部都拥有子控件,在OC机制中,所有控件内部都是以懒加载的形式添加的.我们可以拿到textField中的子控件label,通过监听textField的状态,设置内部子控件label的样式.

    • 方法: 有四中方法:

    • 1, 代理. 2, 通知. 3, target. 4, 是否是第一相应者.

    • 方法一: 使用target方法监听富文本字符串的改变.

    // 1, 首先在xib中描述登录界面
    
    // 2, 新建一个继承于UITextField的类,将xib中的所有TextFiled都绑定这个类.
    // 方法1: 通过富文本字符串来设置样式
    
    - (void)awakeFromNib
    {
    
        // 1, 设置光标的颜色
        self.tintColor = [UIColor whiteColor];
    
        // 2, 监听textField的开始编辑状态
        [self addTarget:self action:@selector(textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
    
        // 3, 监听textField的结束编辑
        [self addTarget:self action:@selector(textFieldEndEditing) forControlEvents:UIControlEventEditingDidEnd];
    
        // 4, 描述占位文字属性
        NSMutableDictionary *attr = [NSMutableDictionary dictionary];
        attr[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
    
        // 5, 富文本属性
        NSAttributedString *attribute = [[NSAttributedString alloc] initWithString:self.placeholder attributes:attr];
    
        self.attributedPlaceholder = attribute;
    
    }
    
    
    • 注意: 当不知道设置某个控件的什么属性时,先去头文件中找,有没有和占位文字相关的属性或者方法.如果实在找不到可以使用runtime,遍历内部的子控件,拿到它对应的控件设置属性值即可.
    #pragma mark - 事件监听方法
    
    // 监听开始编辑
    - (void)textFieldBeginEditing {
    
        // 1, 描述占位文字属性
        NSMutableDictionary *attr = [NSMutableDictionary dictionary];
        attr[NSForegroundColorAttributeName] = [UIColor whiteColor];
    
        // 2, 富文本属性
        NSAttributedString *attribute = [[NSAttributedString alloc] initWithString:self.placeholder attributes:attr];
    
        self.attributedPlaceholder = attribute;
    
    }
    
    // 监听结束编辑
    - (void)textFieldEndEditing {
    
        // 4, 描述占位文字属性
        NSMutableDictionary *attr = [NSMutableDictionary dictionary];
        attr[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
    
        // 5, 富文本属性
        NSAttributedString *attribute = [[NSAttributedString alloc] initWithString:self.placeholder attributes:attr];
    
        self.attributedPlaceholder = attribute;
    }
    

    方法二 :

    • 不使用富文本字符串的形式修改占位文字的字体颜色.因为重复代码太多.前面讲过最好是直接给对象控件设置颜色.TextFiled和Button一样,内部之所以能够显示文字,是因为其内部包含有label.所以只要我们,拿到这个占位用的label,就可以直接设置颜色.
    • 主要思路: 方法二的主要思路是利用KVC思想,拿到TextFiled内部中的子控件,在使用KVC之前,用runtime变出TextFiled中所有子控件,找到placeholderLabel即可.
    - (void)awakeFromNib
    {
        UITextField *textFiled;
        // 1.设置光标
        self.tintColor = [UIColor whiteColor];
    
        // 监听开始编辑
        [self addTarget:self action:@selector(textBegin) forControlEvents:UIControlEventEditingDidBegin];
    
        // 监听结束编辑
        [self addTarget:self action:@selector(textEnd) forControlEvents:UIControlEventEditingDidEnd];
    
        // 根据属性名获取这个属性的值
        UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
    
        placeholderLabel.textColor = [UIColor lightGrayColor];
    
    }
    
    // 文本框开始编辑
    - (void)textBegin
    {
        // 修改占位文字样式
        // 根据属性名获取这个属性的值
        UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
    
        placeholderLabel.textColor = [UIColor whiteColor];
    }
    
    // 文本框结束编辑
    - (void)textEnd
    {
        // 根据属性名获取这个属性的值
        UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
    
        placeholderLabel.textColor = [UIColor lightGrayColor];
    }
    
    • 注意 : 这样设置相对上一中方法来说就相对比较简洁一点.但是,我们最好是将设置封装到一个分类中,提高代码的复用.

    封装代码

    - (void)awakeFromNib
    {
        // 1.设置光标
        self.tintColor = [UIColor whiteColor];
    
        // 监听开始编辑
        [self addTarget:self action:@selector(textBegin) forControlEvents:UIControlEventEditingDidBegin];
    
        // 监听结束编辑
        [self addTarget:self action:@selector(textEnd) forControlEvents:UIControlEventEditingDidEnd];
    
        // 根据属性名获取这个属性的值
        self.placeholderColor = [UIColor lightGrayColor];
    }
    
    // 文本框开始编辑
    - (void)textBegin
    {
        // 修改占位文字样式
        self.placeholderColor = [UIColor whiteColor];
    }
    
    // 文本框结束编辑
    - (void)textEnd
    {
        self.placeholderColor = [UIColor lightGrayColor];
    }
    
    
    • 定义一个分类,将设置占位文字颜色的具体实现封装到分类中.
    .h文件
    // 需要将属性定义在.h文件中,方便外界调用
    // 设置占位文字颜色
    @property UIColor *placeholderColor;
    
    #import "UITextField+Placeholder.h"
    #import <objc/message.h>
    // runtime:主要目的操作系统的类
    
    // OC系统自带控件中,所有的子控件都是懒加载
    @implementation UITextField (Placeholder)
    
    + (void)load
    {
        Method setPlaceholderMethod = class_getInstanceMethod(self, @selector(setPlaceholder:));
         Method wg_setPlaceholderMethod = class_getInstanceMethod(self, @selector(wg_setPlaceholder:));
    
        // 交互方法
        method_exchangeImplementations(setPlaceholderMethod, wg_setPlaceholderMethod);
    
    }
    
    // 设置占位文字颜色
    - (void)setPlaceholderColor:(UIColor *)placeholderColor
    {
        // 1.保存占位文字颜色到系统的类,关联
        // object:保存到哪个对象中
        // key:属性名
        // value:属性值
        // policy:策略
        objc_setAssociatedObject(self, @"placeholderColor", placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
        UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
        placeholderLabel.textColor = placeholderColor;
    }
    
    - (UIColor *)placeholderColor
    {
        return objc_getAssociatedObject(self, @"placeholderColor");
    }
    
    - (void)wg_setPlaceholder:(NSString *)placeholder
    {
        // 设置占位文字
        [self wg_setPlaceholder:placeholder];
    
        // 设置占位文字颜色
        self.placeholderColor = self.placeholderColor;
    }
    
    
    • 知识拓展: 在使用代理时,最好不要让自己成为自己的代理,虽然不会报错,但是不符合代理的原理.所以,建议不要使用这种方法,上面所述的方法.主要是想知道有这么个方法和过程.在实际开发中我会运用的方法如下:

    使用Target监听TextField内部控件的私有属性.

    • 首先是使用运行时机制获取某个控件内部的私有属性
    // 1, 获取私有属性
        // 运行时获取类中的私有属性
        unsigned int count;
        // 运行时打印出文本框中的所有成员属性
        Ivar *ivarList = class_copyIvarList([UITextField class], &count);
        for (int i =0; i< count; i++) {
            Ivar ivar = ivarList[i];
    
            NSLog(@"%s",ivar_getName(ivar));
        }
        free(ivarList);
    
    
    • 其次将从遍历出来的属性中找到想要修改的属性
    // 2, 找到对应的私有属性,将它设置为一个宏
    static NSString * const WGPlaceholderLabel = @"placeholderLabel.textColor";
    
    
    • 然后监听私有属性
        // 设置占位文字原有颜色
        [self setValue:[UIColor grayColor] forKeyPath:WGPlaceholderLabel];
    
        // 监听文本框开始编辑
        [self addTarget:self action:@selector(editingBegin) forControlEvents:UIControlEventEditingDidBegin];
    
        // 监听文本框结束编辑
        [self addTarget:self action:@selector(editingEnd) forControlEvents:UIControlEventEditingDidEnd];
    
    
    • 最后实现监听方法
    #pragma mark - 监听文本框的编辑状态
    
    - (void)editingBegin{
    
        [self setValue:[UIColor whiteColor] forKeyPath:WGPlaceholderLabel];
    }
    
    - (void)editingEnd {
    
       [self setValue:[UIColor grayColor] forKeyPath:WGPlaceholderLabel];
    }
    
    • 总结:
    • 1, 文本框和按钮一样,都可以编辑文字,所以内部是有label的,所以需要拿到文本框中的label(可以在"小面包中检测"),当输入文字后,有个label就会消失,那个就是占位label,所以需要拿到系统内部的私有属性,但是不能直接拿到私有的属性和方法,所以需要用到KVC去取值和赋值.通过"运行时"拿到属性
    • 2, 然后通过KVC取值
      容易出错点: 不要用setValu:forKey,程序会崩掉,要用forKeyPath:表示不管你在文件的那一层都能去拿到

    代理(不推荐使用)

    • 这里使用代理需要注意一点:它是自己成为了自己的代理,虽然可以实现项目需求,但是,这和"代理"的本质有冲突.
    • 代理本质: 自己不能做的事,让自己的代理去做
    /*
     总结: 本章是用代理的方式监听文本框的编辑状态,然后通过拿到UITextField中的私有的_placeholderLabel属性,给私有属性赋值即可,通过运行时获取查看其内部的所有私有属性,然后通过KVC赋值;
     */
    
    #import "WGLoginRegisterTextFiled.h"
    #import <objc/message.h>
    
    static NSString * const WGPlaceholderLabel = @"_placeholderLabel.textColor";
    
    @interface WGLoginRegisterTextFiled () <UITextFieldDelegate>
    @end
    @implementation WGLoginRegisterTextFiled
    
    - (void)awakeFromNib {
    
        // 设置光标颜色
        self.tintColor = [UIColor cyanColor];
    
        // 通过运行时获取TextFiled的内部私有属性
        unsigned int count ;
        Ivar *ivarList = class_copyIvarList([UITextField class], &count);
        // 遍历UITextField的所有属性,ivarList(指针)实质是一个数组
    
        for (int i = 0; i < count; i++) {
    
            // 获取每一个属性
            Ivar ivar = ivarList[i];
    
            NSLog(@"%s",ivar_getName(ivar));  // "%s"原因是运行时是一个C语言的语法
    
        }
    
        // 销毁运行时创建的ivarList
        free(ivarList);
    
        // 通过KVC将属性取出来并赋值
        [self setValue:[UIColor grayColor] forKeyPath:WGPlaceholderLabel];
    
        // 设置代理
        self.delegate = self; // 自己成为自己的代理,在实际开发中不这样写,这和代理的原理意义上违背了
    
    }
    
    #pragma mark - 设置代理的方法
    
    // 开始编辑
    - (void)textFieldDidBeginEditing:(UITextField *)textField {
    
        // KVC
        [self setValue:[UIColor whiteColor] forKeyPath:WGPlaceholderLabel];
    
    }
    
    // 结束编辑
    - (void)textFieldDidEndEditing:(UITextField *)textField {
    
        [self setValue:[UIColor grayColor] forKeyPath:WGPlaceholderLabel];
    
    }
    

    根据某些控件特有的方法或者属性来设置

    • TextFiled有一个特别的属性方法:即是否成为第一响应者和不当第一响应者.根据这样的特性做一些操作.
    /*
     分析:UITextField有一个特有的属性,就是响应者属性,通过重写成为第一响应者和辞去第一响应者来给占位文字设置颜色
    
    
     */
    #import "WGLoginRegisterTextFiled.h"
    #import <objc/message.h>
    
    static NSString * const WGPlaceholderLabel = @"_placeholderLabel.textColor";
    
    @interface WGLoginRegisterTextFiled () <UITextFieldDelegate>
    @end
    @implementation WGLoginRegisterTextFiled
    
    - (void)awakeFromNib {
    
        // 设置光标颜色
        self.tintColor = [UIColor cyanColor];
    
        // 通过KVC将属性取出来并赋值
        [self setValue:[UIColor grayColor] forKeyPath:WGPlaceholderLabel];
    
        // 调用时刻: 当成为第一响应者 /获取焦点 /弹出键盘
        [self becomeFirstResponder];
    
        // 调用时刻: 当失去第一响应者 /获取焦点 /弹出键盘
        [self resignFirstResponder];
    
    }
    
    #pragma mark - 设置代理的方法
    
    
    // 调用时刻: 当成为第一响应者 /获取焦点 /弹出键盘
    - (BOOL)becomeFirstResponder {
    
        [self setValue:[UIColor whiteColor] forKeyPath:WGPlaceholderLabel];
    
        return [super becomeFirstResponder];
    }
    
    // 调用时刻: 当失去第一响应者 /获取焦点 /弹出键盘
    - (BOOL)resignFirstResponder {
    
        [self setValue:[UIColor grayColor] forKeyPath:WGPlaceholderLabel];
    
       return [super resignFirstResponder];
    
    }
    @end
    
    
    • 总结:其实还有通知方法的,和代理类似,所以就不写了.本章重点.

    • 1, 学会编程思想,不要局限于某一种方式开发

    • 2, 学会利用某些特有的方法或者属性来解决问题

    • 3, 如果有时间可以深入学习运行时机制(特别有意思)

    • 知识拓展: 在使用代理时,最好不要让自己成为自己的代理,虽然不会报错,但是不符合代理的原理.所以,建议不要使用这种方法

    • 注意: 本章使用的target监听textFiled的编辑状态,但是这是不符合代理的原理,在实际开发中"尽量不要自己成为自己的代理".我的建议是使用textFiled的特性,即"第一响应者"来监听textFiled的编辑状态.

    相关文章

      网友评论

        本文标题:关于设置TextFiled中占位文字的颜色的几个方法

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