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

欢迎"@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的编辑状态.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容