需求:
1.通過不同狀態(tài)調(diào)整TextField占位文字顏色
2.編輯狀態(tài)下為WhiteColor
;默認LightGrayColor
文字描述較為抽象,直接看效果圖:
實現(xiàn)方式一
實現(xiàn)思路:
設(shè)置TextField
代理,實現(xiàn)<UITextFieldDelegate>
協(xié)議方法,在開始編輯時,通過富文本直接對TextField
的attributedPlaceholder
賦值,同理,在編輯結(jié)束后同樣操作
當(dāng)然,在為TextField
設(shè)置占位文字時,也需要通過富文本對attributedPlaceholder
屬性進行賦值
- (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;
}
實現(xiàn)方式二
實現(xiàn)思路:
實現(xiàn)代理的方式有點大材小用了,其實還可以addTarget
的方式
分別在UIControlEventEditingDidBegin
和UIControlEventEditingDidEnd
中做上面的操作
實現(xiàn)方式三
實現(xiàn)思路:
通知,在自定義TextField
中,分別監(jiān)聽UITextFieldTextDidBeginEditingNotification
和UITextFieldTextDidEndEditingNotification
,在接收到對應(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];
注意點:
自定義的
TextField
默認注冊了通知,也就意味著實例化出的每一個實例都注冊了通知,因此一旦接受到了通知,整個視圖內(nèi)自定義的TextField
都會去響應(yīng)對應(yīng)的方法
e.g. 我這個界面,有兩個文本框(賬號
和密碼
),當(dāng)賬號
輸入框獲取焦點時,密碼
也接收到了通知,修改占位文本框字體顏色會讓兩個文本框同時發(fā)生改變,并不能滿足我們的需求(獲取焦點時白色,失去焦點的灰色),所以要做限制處理,讓賬號
和密碼
輸入框只監(jiān)聽自己發(fā)出的通知,也就是在自定義TextField
注冊通知時,將object
參數(shù)傳入自己,這樣就滿足了每一個文本框只監(jiān)聽自己發(fā)出的通知在收到
TextField
發(fā)布通知執(zhí)行的方法中,通過參數(shù)notification.object
獲取到對應(yīng)的TextField
,執(zhí)行后面的操作使用通知,切記在
dealloc
中移除通知
實現(xiàn)方式四
實現(xiàn)思路:
1.自定義TextField
;
2.通過RunTime
獲取到私有屬性placeholderLabel
占位文本框;
3.重寫layoutSubviews
方法,根據(jù)當(dāng)前TextField
狀態(tài)通過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"];
}
}
實現(xiàn)方式五
實現(xiàn)思路:
重寫becomeFirstResponder
和resignFirstResponder
方法,分別對當(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];
}
但需要注意一點,因為TextField
在實例化時,默認并未設(shè)置placeholder
屬性,TextField
內(nèi)部子控件placeholderLabel
采用一種懶加載機制,此時相當(dāng)于為nil
,如果在自定義TextField
的init
方法中直接通過KVC
方式設(shè)置默認狀態(tài)顏色是無意的,必須要保證在placeholderLabel
存在的前提下設(shè)置才會有意義,而設(shè)置延遲的方式并不能完美解決這個問題,文字描述可能比較抽空,直接看圖便能更容易的發(fā)現(xiàn)這個問題:
雖然beignEdit
和endEdit
下的狀態(tài)正常,但是剛剛展示視圖時,TextField
的占位文字還是黑色,暫時想到的方法就是在layoutSubViews
方法中(方式四中),將未編輯狀態(tài)下設(shè)置成灰色
總結(jié):
- 方式一和方式二比較簡單粗暴,思路上仍以理解,直接利用了
TextField
的attributedPlaceholder
屬性,使用了富文本,而且需要在父視圖設(shè)置代理,實現(xiàn)協(xié)議方法或?qū)崿F(xiàn)監(jiān)聽事件;
當(dāng)然通過
協(xié)議
/addTarget
的方式,也可以封裝到TextField
內(nèi)部
① 將代理設(shè)置給自己,實現(xiàn)協(xié)議方法,但這種將代理設(shè)置給自己的方式不推薦使用,因為代理模式為一對一,我們將TextField
的代理對象設(shè)置給了自己,而外界使用TextField
并設(shè)置代理后,問題就來了
② 而addTarget
的方式不受影響,在TextField
內(nèi)部添加自己監(jiān)聽狀態(tài),在外界添加控制器監(jiān)聽TextField
狀態(tài),當(dāng)條件滿足時,TextField
和控制器
都會分別響應(yīng)自身內(nèi)部的事件,不受影響
- 方式三,通知和代理、addTarget的思路類似,但是性能略差一些,而且照此需求實現(xiàn)的注意點相對其他方式較多
通知的特點是方法執(zhí)行所在線程取決于監(jiān)聽通知的位置,比如在主線程監(jiān)聽通知,那么收到通知后,方法將在主線程執(zhí)行,反之則在子線程,而大部分的系統(tǒng)方法均在主線程執(zhí)行,除了最常使用的
addObserver:
,還可以用另外一種指定線程的方式:
self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[[NSOperationQueue alloc] init] usingBlock:^(NSNotification * _Nonnull note) {
// 執(zhí)行代碼
}];
- 方式四會使父視圖或控制器的代碼更加簡潔,關(guān)于TextField樣式的問題,完全封裝到自定義控件內(nèi)部,不需要外界考慮,使用更加靈活,同時又不需要過多的考慮,比如通知的監(jiān)聽鸠姨、移除,代理對外的影響等.
- 方式五的實現(xiàn)也較為簡單,只是需要注意
TextField
初始默認狀態(tài)的設(shè)置時機