調(diào)整TextField占位文字顏色

需求:
1.通過(guò)不同狀態(tài)調(diào)整TextField占位文字顏色
2.編輯狀態(tài)下為WhiteColor;默認(rèn)LightGrayColor
文字描述較為抽象,直接看效果圖:

01-占位文字顏色效果.gif

實(shí)現(xiàn)方式一

實(shí)現(xiàn)思路:
設(shè)置TextField代理,實(shí)現(xiàn)<UITextFieldDelegate>協(xié)議方法,在開(kāi)始編輯時(shí),通過(guò)富文本直接對(duì)TextFieldattributedPlaceholder賦值,同理,在編輯結(jié)束后同樣操作

當(dāng)然,在為TextField設(shè)置占位文字時(shí),也需要通過(guò)富文本對(duì)attributedPlaceholder屬性進(jìn)行賦值

- (void)textFieldDidBeginEditing:(JSLoginTextField *)textField {
    NSMutableAttributedString *placeholderText = [[NSMutableAttributedString alloc] initWithAttributedString:textField.attributedPlaceholder];
    [placeholderText addAttribute:NSForegroundColorAttributeName value:[UIColor whiteColor] range:NSMakeRange(0, placeholderText.length)];
    textField.attributedPlaceholder = placeholderText;
}
- (void)textFieldDidEndEditing:(JSLoginTextField *)textField {
    NSMutableAttributedString *placeholderText = [[NSMutableAttributedString alloc] initWithAttributedString:textField.attributedPlaceholder];
    [placeholderText addAttribute:NSForegroundColorAttributeName value:[UIColor lightGrayColor] range:NSMakeRange(0, placeholderText.length)];
    textField.attributedPlaceholder = placeholderText;
}

實(shí)現(xiàn)方式二

實(shí)現(xiàn)思路:
實(shí)現(xiàn)代理的方式有點(diǎn)大材小用了,其實(shí)還可以addTarget的方式
分別在UIControlEventEditingDidBeginUIControlEventEditingDidEnd中做上面的操作


實(shí)現(xiàn)方式三

實(shí)現(xiàn)思路:
通知,在自定義TextField中,分別監(jiān)聽(tīng)UITextFieldTextDidBeginEditingNotificationUITextFieldTextDidEndEditingNotification,在接收到對(duì)應(yīng)通知后,在方法中執(zhí)行上面的操作

[[NSNotificationCenter  defaultCenter] addObserver:self selector:@selector(beingEditing:) name:UITextFieldTextDidBeginEditingNotification object:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endEditing:) name:UITextFieldTextDidEndEditingNotification object:self];
注意點(diǎn):
  • 自定義的TextField默認(rèn)注冊(cè)了通知,也就意味著實(shí)例化出的每一個(gè)實(shí)例都注冊(cè)了通知,因此一旦接受到了通知,整個(gè)視圖內(nèi)自定義的TextField都會(huì)去響應(yīng)對(duì)應(yīng)的方法

    e.g. 我這個(gè)界面,有兩個(gè)文本框(賬號(hào)密碼),當(dāng)賬號(hào)輸入框獲取焦點(diǎn)時(shí),密碼也接收到了通知,修改占位文本框字體顏色會(huì)讓兩個(gè)文本框同時(shí)發(fā)生改變,并不能滿足我們的需求(獲取焦點(diǎn)時(shí)白色,失去焦點(diǎn)的灰色),所以要做限制處理,讓賬號(hào)密碼輸入框只監(jiān)聽(tīng)自己發(fā)出的通知,也就是在自定義TextField注冊(cè)通知時(shí),將object參數(shù)傳入自己,這樣就滿足了每一個(gè)文本框只監(jiān)聽(tīng)自己發(fā)出的通知

  • 在收到TextField發(fā)布通知執(zhí)行的方法中,通過(guò)參數(shù)notification.object獲取到對(duì)應(yīng)的TextField,執(zhí)行后面的操作

  • 使用通知,切記在dealloc中移除通知


實(shí)現(xiàn)方式四

實(shí)現(xiàn)思路:
1.自定義TextField;
2.通過(guò)RunTime獲取到私有屬性placeholderLabel占位文本框;
3.重寫(xiě)layoutSubviews方法,根據(jù)當(dāng)前TextField狀態(tài)通過(guò)KVC設(shè)置占位文本框字體顏色

- (void)layoutSubviews {
    [super layoutSubviews];
    if (self.isEditing) {
        [self setValue:[UIColor whiteColor] forKeyPath:@"placeholderLabel.textColor"];
    } else {
        // KVC 修改 占位文字顏色
        [self setValue:[UIColor lightGrayColor] forKeyPath:@"placeholderLabel.textColor"];
    }
}

實(shí)現(xiàn)方式五

實(shí)現(xiàn)思路:
重寫(xiě)becomeFirstResponderresignFirstResponder方法,分別對(duì)當(dāng)前TextField處理

- (void)layoutSubviews {
    [super layoutSubviews];
    if (!self.isEditing) {
        [self setValue:[UIColor lightGrayColor] forKeyPath:@"placeholderLabel.textColor"];
    }
}
- (BOOL)becomeFirstResponder {
    [self setValue:[UIColor whiteColor] forKeyPath:@"placeholderLabel.textColor"];
    return [super becomeFirstResponder];
}

- (BOOL)resignFirstResponder {
    [self setValue:[UIColor lightGrayColor] forKeyPath:@"placeholderLabel.textColor"];
    return [super resignFirstResponder];
}

但需要注意一點(diǎn),因?yàn)?code>TextField在實(shí)例化時(shí),默認(rèn)并未設(shè)置placeholder屬性,TextField內(nèi)部子控件placeholderLabel采用一種懶加載機(jī)制,此時(shí)相當(dāng)于為nil,如果在自定義TextFieldinit方法中直接通過(guò)KVC方式設(shè)置默認(rèn)狀態(tài)顏色是無(wú)意的,必須要保證在placeholderLabel存在的前提下設(shè)置才會(huì)有意義,而設(shè)置延遲的方式并不能完美解決這個(gè)問(wèn)題,文字描述可能比較抽空,直接看圖便能更容易的發(fā)現(xiàn)這個(gè)問(wèn)題:

02-占位文字顏色效果.gif

雖然beignEditendEdit下的狀態(tài)正常,但是剛剛展示視圖時(shí),TextField的占位文字還是黑色,暫時(shí)想到的方法就是在layoutSubViews方法中(方式四中),將未編輯狀態(tài)下設(shè)置成灰色


總結(jié):

  • 方式一和方式二比較簡(jiǎn)單粗暴,思路上仍以理解,直接利用了TextFieldattributedPlaceholder屬性,使用了富文本,而且需要在父視圖設(shè)置代理,實(shí)現(xiàn)協(xié)議方法或?qū)崿F(xiàn)監(jiān)聽(tīng)事件;

當(dāng)然通過(guò)協(xié)議/addTarget的方式,也可以封裝到TextField內(nèi)部
① 將代理設(shè)置給自己,實(shí)現(xiàn)協(xié)議方法,但這種將代理設(shè)置給自己的方式不推薦使用,因?yàn)榇砟J綖橐粚?duì)一,我們將TextField的代理對(duì)象設(shè)置給了自己,而外界使用TextField并設(shè)置代理后,問(wèn)題就來(lái)了
② 而addTarget的方式不受影響,在TextField內(nèi)部添加自己監(jiān)聽(tīng)狀態(tài),在外界添加控制器監(jiān)聽(tīng)TextField狀態(tài),當(dāng)條件滿足時(shí),TextField控制器都會(huì)分別響應(yīng)自身內(nèi)部的事件,不受影響

  • 方式三,通知和代理、addTarget的思路類似,但是性能略差一些,而且照此需求實(shí)現(xiàn)的注意點(diǎn)相對(duì)其他方式較多

通知的特點(diǎn)是方法執(zhí)行所在線程取決于監(jiān)聽(tīng)通知的位置,比如在主線程監(jiān)聽(tīng)通知,那么收到通知后,方法將在主線程執(zhí)行,反之則在子線程,而大部分的系統(tǒng)方法均在主線程執(zhí)行,除了最常使用的addObserver:,還可以用另外一種指定線程的方式:

self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[[NSOperationQueue alloc] init] usingBlock:^(NSNotification * _Nonnull note) {
        // 執(zhí)行代碼
    }];
  • 方式四會(huì)使父視圖或控制器的代碼更加簡(jiǎn)潔,關(guān)于TextField樣式的問(wèn)題,完全封裝到自定義控件內(nèi)部,不需要外界考慮,使用更加靈活,同時(shí)又不需要過(guò)多的考慮,比如通知的監(jiān)聽(tīng)、移除,代理對(duì)外的影響等.
  • 方式五的實(shí)現(xiàn)也較為簡(jiǎn)單,只是需要注意TextField初始默認(rèn)狀態(tài)的設(shè)置時(shí)機(jī)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容