一、我們通常在設計登錄界面時會用到UITextField,如下圖所示:
通常想實現(xiàn)下面幾點:
1、左邊顯示圖片
2、textField中添加默認的占位符(提示文字),并且希望占位符和左邊圖片有一點的距離,或者讓占位符居中,
3、點擊textField輸入時光標的位置應該緊在占位符左側,并緊挨著占位符
最終實現(xiàn)效果如下圖所示:
4.如何更好地限制一個UITextField的輸入長度

二、左邊顯示圖片很簡單下面幾行代碼搞定(右邊顯示圖片同理):
UIImageView *passwordImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"passwordIcon"]];
password.leftView = passwordImage;
password.leftViewMode = UITextFieldViewModeAlways;
提示:上下兩個圖片的寬度要保持一致,不然會導致占位符的左邊無法對其!
三、而設置占位符的位置和編輯狀態(tài)時光標的位置試了很多方法感覺都不好使,最終找到一個方法,自定義一個basicTextField繼承自UITextField;然后可以重寫下面的幾個方法:
- (CGRect)borderRectForBounds:(CGRect)bounds;
- (CGRect)textRectForBounds:(CGRect)bounds;
- (CGRect)placeholderRectForBounds:(CGRect)bounds;
- (CGRect)editingRectForBounds:(CGRect)bounds;
- (CGRect)clearButtonRectForBounds:(CGRect)bounds;
- (CGRect)leftViewRectForBounds:(CGRect)bounds;
- (CGRect)rightViewRectForBounds:(CGRect)bounds;
四、下面是具體的代碼實現(xiàn):
(1)設置左視圖
- (CGRect)leftViewRectForBounds:(CGRect)bounds{
CGRect iconRect = [super leftViewRectForBounds:bounds];
iconRect.origin.x += 10;
return iconRect;
}
(2)重寫占位符的x值
- (CGRect)placeholderRectForBounds:(CGRect)bounds{
CGRect placeholderRect = [super placeholderRectForBounds:bounds];
placeholderRect.origin.x += 1;
return placeholderRect;
}
(3)重寫文字輸入時的X值
- (CGRect)editingRectForBounds:(CGRect)bounds{
CGRect editingRect = [super editingRectForBounds:bounds];
editingRect.origin.x += 20;
return editingRect;
}
(4)重寫文字顯示時的X值
- (CGRect)textRectForBounds:(CGRect)bounds{
CGRect textRect = [super editingRectForBounds:bounds];
textRect.origin.x += 20;
return textRect;
}
第四個問題:如何更好地限制一個UITextField的輸入長度
要限制一個UITextField的輸入字數(shù)(參考鏈接),首先想到的應該是通過
UITextFieldDelegate
的代理方法來限制
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
比如要設置字數(shù)限制為20:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == self.titleField) {
if (textField.length > 20) return NO;
}
return YES;
}
但是這樣的限制簡單粗暴,可能會影響用戶正常邏輯下的輸入,比如輸入了20個字符后,要退格回刪字符。
這時候我們可能會考慮“Detect backspace in UITextField”,比如簡單地判斷replacementString的長度是否為0。
接著我們可能還會遇到用戶已經輸入20個字符了,這時候繼續(xù)輸入---不過是選擇了部分文本進行替換-----無法進行了,這也妨礙了用戶的正常操作,所以限制的代碼版本可能會演進為:
#pragma mark - UITextFieldDelegate
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField == self.titleField) {
if (string.length == 0) return YES;
NSInteger existedLength = textField.text.length;
NSInteger selectedLength = range.length;
NSInteger replaceLength = string.length;
if (existedLength - selectedLength + replaceLength > 20) {
return NO;
}
}
return YES;
}
到這里可能會覺得基本大功告成了,但是當你輸入19個字符后,第20個字符以中文漢字的形式繼續(xù)輸入,那么系統(tǒng)會在鍵盤上方提供后續(xù)的一系列聯(lián)想詞,你會發(fā)現(xiàn)通過這種方式可以連續(xù)選字輸入從而突破20個字符的限制。WTF
到了這里,我們可能會希望有個類似
(void)textFieldDidChange:(UITextField *)textField
的回調方法,但可惜沒有。
當然,我們還可以通過(void)textFieldDidEndEditing:(UITextField *)textField;
回調方法在結束編輯的時候把文本截斷,雖然在用戶體驗上會有點突兀。
不過當我們點進去UITextField.h頭文件里尋覓上述回調方法而不得時,可能會發(fā)現(xiàn)最下面有這么個消息通知名稱:
UIKIT_EXTERN NSString *const UITextFieldTextDidChangeNotification;
不過,監(jiān)聽消息還要記得解除監(jiān)聽,通常我還習慣把監(jiān)聽消息的代碼統(tǒng)一放在一個方法中,看起來有點“大動干戈”。
所幸的是UITextField本身提供了相應的事件監(jiān)聽:
[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
- (void)textFieldDidChange:(UITextField *)textField
{
if (textField == self.titleField) {
if (textField.text.length > 20) {
textField.text = [textField.text substringToIndex:20];
}
}
}