UITextField控制元件的諸多特性都和UITextView相似,比如成為輸入文字焦點時鍵盤自動顯示,支援長按彈出動作選項,能夠接收輸入事件(開始輸入,修改內容,結束輸入和點選回車等)。
1.特有的特
但對於UITextField來說,他又有很多自己獨有的特性:
(1)placeholder.
當UITextField上沒有文字內容時,會以灰色的內容顯示placeholder的內容,並且一點有正式的文字內容輸入並呈現,placeholder內容會隱藏
self.textField.placeholder = @"Please input you userName";
(2)一次性刪除所有內容
如果開發者設定了這個屬性,當它起作用時,會靠近UITextField控制元件後端顯示一個“x”按鈕,當使用者點選此按鈕時,所有之前的UITextField上輸入的內容都會被刪除。
IOS提供了針對這個“X”按鈕的四種顯示時機,分別是永不顯示,當輸入時顯示,當輸入時不顯示,一直顯示,如果用程式碼的話,則是對clearButtonMode的屬性設定為下列系統常量之一。
typedef NS_ENUM(NSInteger, UITextFieldViewMode)
{
UITextFieldViewModeNever,
UITextFieldViewModeWhileEditing,
UITextFieldViewModeUnlessEditing,
UITextFieldViewModeAlways
};
設定程式碼如下:
self.textField.clearButtonMode=UITextFieldViewModeAlways;
(3)輸入內容的清空時機
預設的UITextField的內容如果不點選清空按鈕或者鍵盤的回退按鈕,並不會無故被清掉。但是如果UITextField的內容是保密特性時,這個預設的清空內容機制變成了每次開始輸入新內容時,上一次的內容自動清空。
而UITextField還提供了另一種清空機制,當每次焦點移動到UITextField上彈出鍵盤時,上一次內容自動清空(預設需要輸入才會清空),這個設定實現程式碼如下:
self.textField.clearsOnBeginEditing = YES;
(4)四種UITextField邊框式樣供挑選
四種邊框式樣分別是無邊框,黑線邊框,貝澤爾帶陰影邊框,圓角邊框。並且當式樣非圓角邊框時,開發者可以自定義UITextField的背景圖片,考慮到UITextField的細長性和可拉伸性,所提供的圖片也要是可拉伸的。
3.可拉伸圖片
所謂可拉伸的圖片,是指提供的圖片無論橫向還是縱向都不用提供全部畫素,當某個情況下圖片所要放置的地方的橫向或縱向數值比圖片本身大時,此圖片有能力以自己橫向某一行或縱向某一列畫素點為依據進行自我拉伸。其實這個所謂的拉伸,就是系統對某些由開發者指定的畫素進行簡單複製而已。
IOS6以後的拉伸方法如下:
self.textField.background=[[UIImage imageNamed:@"back.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 8.0f, 0.0f, 8.0f)];
其中使用到的是Inset即內縮排的概念,內縮排的生成方法:
UIEdgeINsets UIEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right);
這裡UIEdgeInsetsMake的意思就是我們從左邊數起8個畫素,右邊數起8個像數,這樣剩餘中間畫素自然就成了系統的橫向拉伸點。開發者當然也可以將這個數字8理解成左邊數起多少個畫素保持不變,右邊數起多少個畫素保持不變,原理是一樣的。
4.避免被鍵盤擋住
和UITextView不同,UITextField由於高度只有固定的30px.並且不像UITextView可以對內容進行滾動。所以再輸入時,如果從螢幕底下彈出的鍵盤將UITextField控制元件不幸給遮蓋住了的話,將非常影響使用者體驗,甚至造成無法繼續程式工作流程的漏洞。
所以如果專案中有類似處於螢幕較低位置UITextField控制元件存在的情況發生時,開發者需要考慮將UITextField動態地向上移動到使用者能夠看到全貌的地方。
我們來做個簡單地例子:
如圖所示:
當然,如果我們使用UIScrollView作為控制元件的載體會更方便,不過這裡我們關心的是做法,目的和實現原理是差不多的。所以我們使用普通的UIView類 的物件contentView即可。
隨後將“使用者名稱”UITextField控制元件的鍵盤迴車鍵設定成“Next”的式樣,以期望點選後將焦點移到“密碼”UITextField物件,而“密碼”UITextField的n返回鍵可以設定成“Done”式樣,以期望點選後收起鍵盤。
首先設定屬性:
1 @property (weak, nonatomic) IBOutlet UITextField *txtUserName; 2 @property (weak, nonatomic) IBOutlet UITextField *txtPassword; 3 @property (strong, nonatomic) IBOutlet UIView *contentView;
隨後為程式增加兩個對於鍵盤顯示和隱藏的系統訊息監視,這樣當鍵盤顯示和隱藏時,系統能夠回撥到相應的處理函式
- (void)viewDidLoad { [super viewDidLoad]; self.txtUserName.delegate=self; self.txtPassword.delegate=self; // Do any additional setup after loading the view, typically from a nib. //鍵盤顯示訊息的回撥函式 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil]; //鍵盤隱藏訊息的回撥函式 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHidden:) name:UIKeyboardWillHideNotification object:nil]; }
之後就是對顯示鍵盤的回撥函式keyboardDidShown的撰寫,具體程式碼如下:
#pragma mark- #pragma mark Keyboard Notification -(void)keyboardWillShown:(NSNotification *)aNotification { //設定鍵盤顯示的flag _keyboardShowing=YES; //收取訊息內容並獲得鍵盤大小 NSDictionary *info=[aNotification userInfo]; NSValue *aValue=[info objectForKey:UIKeyboardFrameEndUserInfoKey]; //當裝置橫屏時,直接取鍵盤的大小並不準確 //因為系統為鍵盤的檢視增加了一個stransform的內容 //所以這裡有必要進行一次座標轉換,以保證鍵盤大小在特定裝置方向上的準確 CGSize keyboardSize = [self.view convertRect:[aValue CGRectValue] fromView:nil].size; //將鍵盤大小記錄下來 _sizeKeyboard=CGSizeMake(keyboardSize.width, keyboardSize.height); //因為要計算UITextField是不是被鍵盤隱藏了,而鍵盤時顯示在UIWindow上的 //所以UITextField的座標也要轉換到self.view上,再同一層面上的座標比較這樣才有意義 CGRect retTextField=[[_activeTextField superview]convertRect:_activeTextField.frame toView:self.view]; //進行移動 [self moveContentView:self.contentView keyboardSize:_sizeKeyboard textFieldRectOnMainView:retTextField]; } #pragma mark - #pragma mark Utility -(void)moveContentView:(UIView *)aView keyboardSize:(CGSize)sizeKeyboard textFieldRectOnMainView:(CGRect)rectTextField { //UITextField當前是否完全顯示出來 if(CGRectContainsRect(CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)-sizeKeyboard.height), rectTextField)) { //不需要移動 return; } //計算需要移動的距離 //之所以不適用self.view.frame,因為self.view作為程式的根檢視 //所以大小一直是豎屏的大小,橫屏時系統只對根檢視的transform進行配置,高度不變 //既然contentView高度不變,只變Y軸起始點,那不如直接取contentView的高度 float fDelta=sizeKeyboard.height-CGRectGetHeight(aView.frame)+CGRectGetMinY(rectTextField)+CGRectGetHeight(rectTextField); //移動 [UIView animateWithDuration:0.3f animations:^{ aView.frame=CGRectMake(CGRectGetMinX(aView.frame), CGRectGetMinY(aView.frame)-fDelta, CGRectGetWidth(aView.frame), CGRectGetHeight(aView.frame)); }completion:^(BOOL finished) { }]; }
由於有兩個UITextField物件,所以_activeTextField的成員量是記錄了當前焦點中的UITextField物件。剩下的鍵盤隱藏訊息處理函式keyboardWillHidder程式碼如下:
-(void)keyboardWillHidden:(NSNotification *)aNotification { //沒有焦點中的UITextField了 _activeTextField=nil; //設定鍵盤未顯示的flag _keyboardShowing=NO; //將contentView的座標移動回(0.0,0.0)點 [UIView animateWithDuration:0.3f animations:^{ self.contentView.frame=CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.contentView.frame), CGRectGetHeight(self.contentView.frame)); }completion:^(BOOL finished) { }]; }
最後我們需要考慮到UITextField兩個物件之間的焦點轉移問題和鍵盤的隱藏問題
#pragma mark- #pragma mark UITextField Delegate //焦點進入UITextField後,可以開始輸入的回撥函式 -(void)textFieldDidBeginEditing:(UITextField *)textField { //當前焦點的UITextField _activeTextField=textField; //如果沒有顯示鍵盤,哪移動的任務交給keyboardWillShown:來做,這裡return //否則的話,移動的任務在這裡完成 if(!_keyboardShowing) { return; } //顯然,能夠走到這裡,是因為Next的關係 //我們要和keyboardWillShown裡面寫的一樣,將有效的UITextField位置取出來 //檢查是否需要移位 CGRect rectTextField=[[_activeTextField superview]convertRect:_activeTextField.frame toView:self.view]; //contentView的移動必須性檢查和執行移動 [self moveContentView:self.contentView keyboardSize:_sizeKeyboard textFieldRectOnMainView:rectTextField]; } //點選UITextField對應的鍵盤的Enter鍵的回撥函式 -(BOOL)textFieldShouldReturn:(UITextField *)textField { //按了“Next” if(textField == self.txtUserName) { [self.txtPassword becomeFirstResponder]; return YES; } //按了“Done” if(textField == self.txtPassword) { [self.view endEditing:YES]; return YES; } return YES; }