1. 程式人生 > >IOS: iPhone鍵盤通知與鍵盤定製

IOS: iPhone鍵盤通知與鍵盤定製

一.鍵盤通知

當文字View(如UITextField,UITextView, UIWebView內的輸入框)進入編輯模式成為first responder時,系統會自動顯示鍵盤。成為firstresponder可能由使用者點選觸發,也可向文字View傳送becomeFirstResponder訊息觸發。當文字檢視退出first responder時,鍵盤會消失。文字View退出first responder可能由使用者點選鍵盤上的Done或Return鍵結束輸入觸發,也可向文字View傳送resignFirstResponder訊息觸發。

UIKeyboardFrameBeginUserInfoKey,UIKeyboardFrameEndUserInfoKey對應的Value是個NSValue物件,內部包含CGRect結構,分別為鍵盤起始時和終止時的位置資訊。

UIKeyboardAnimationCurveUserInfoKey對應的Value是NSNumber物件,內部為UIViewAnimationCurve型別的資料,表示鍵盤顯示或消失的動畫型別。

UIKeyboardAnimationDurationUserInfoKey對應的Value也是NSNumber物件,內部為double型別的資料,表示鍵盤h顯示或消失時動畫的持續時間。

例如,在UIKeyboardWillShowNotification,UIKeyboardDidShowNotification通知中的userInfo內容為

userInfo = {
    UIKeyboardAnimationCurveUserInfoKey = 0;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 588}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";
    UIKeyboardFrameChangedByUserInteraction = 0;
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";
}

在UIKeyboardWillHideNotification,UIKeyboardDidHideNotification通知中的
userInfo內容為:

userInfo = {
    UIKeyboardAnimationCurveUserInfoKey = 0;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 588}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";
    UIKeyboardFrameChangedByUserInteraction = 0;
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";
}

Text,Web, and Editing Programming Guide for iOS中,有如下描述Note: The rectangle contained in the UIKeyboardFrameBeginUserInfoKey and UIKeyboardFrameEndUserInfoKey properties of the userInfo dictionary should be used only for the size information it contains. Do not use the origin of the rectangle (which is always {0.0, 0.0}) in rectangle-intersection operations. Because the keyboard is animated into position, the actual bounding rectangle of the keyboard changes over time.
但從實際獲取的資訊來看,矩形的origin並不為{0.0, 0.0},這裡應該不準確。

二.文字物件與WebView鍵盤設定

2. returnKeyType:鍵盤Return鍵顯示的文字,預設為”Return”,其他可選擇的包括Go,Next,Done,Send,Google等。


若想顯示黑色鍵盤又不想透明露出底部檢視,可以將鍵盤配置成Alert型別的,然後監聽鍵盤顯示的廣播通知,在顯示鍵盤時在鍵盤底部增加一不透明黑色背景檢視。

注:在蘋果的鍵盤示例程式 KeyboardAccessory中,將UITextView鍵盤型別更改為UIKeyboardAppearanceAlert,在iPad模擬器中執行鍵盤並沒有出現黑色透明的效果,不知為何? 在iPhone中UIKeyboardAppearanceAlert設定有效。

設定autocorrect, auto-capitalization屬性。

<input type="text" size="30" autocorrect="off" autocapitalization="on">

設定鍵盤型別:

Text: <input type="text"></input>Telephone: <input type="tel"></input>URL: <input type="url"></input>Email: <input type="email"></input>Zip code: <input type="text" pattern="[0-9]*"></input>

三. 使用鍵盤通知調整文字檢視位置

當文字檢視成為First Responser時在視窗底部會顯示出鍵盤,顯示的鍵盤很可能會將文字檢視蓋住從而無法看到編輯的效果。鍵盤通知的一大用途即在鍵盤顯示或隱藏時獲取到鍵盤的位置資訊,從而可以調整視窗中的文字檢視位置或大小,使其可以在鍵盤上方顯示。

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWasShown:)
            name:UIKeyboardDidShowNotification object:nil];

   [[NSNotificationCenter defaultCenter] addObserver:self
             selector:@selector(keyboardWillBeHidden:)
             name:UIKeyboardWillHideNotification object:nil];

}

2.在鍵盤顯示的通知事件處理中獲取到即將顯示鍵盤的大小,將 UIScrollViewcontentInset設定為鍵盤的frame區域,同樣設定scrollIndicatorInsets保證滾動條不會被鍵盤蓋住。獲取到編輯文字檢視的原點位置,與鍵盤顯示區域比較,若會被鍵盤覆蓋,則調整 contentOffset以使其在鍵盤上方

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your application might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y-kbSize.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

3.在鍵盤消失的通知處理事件中,簡單的將UIScrollView恢復即可

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}

在蘋果的 KeyboardAccessory示例程式中同樣演示了使用鍵盤通知來調整文字檢視位置的程式碼,其中使用了鍵盤通知中的鍵盤動畫時間,從而使文字檢視移動的動畫與鍵盤的顯示和消失同步。

- (void)keyboardWillShow:(NSNotification *)notification {

    /*
     Reduce the size of the text view so that it's not obscured by the keyboard.
     Animate the resize so that it's in sync with the appearance of the keyboard.
     */

    NSDictionary *userInfo = [notification userInfo];

    // Get the origin of the keyboard when it's displayed.
    NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];

    // Get the top of the keyboard as the y coordinate of its origin in self's view's coordinate system. The bottom of the text view's frame should align with the top of the keyboard's final position.
    CGRect keyboardRect = [aValue CGRectValue];
    keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
    CGFloat keyboardTop = keyboardRect.origin.y;
    CGRect newTextViewFrame = self.view.bounds;
    newTextViewFrame.size.height = keyboardTop - self.view.bounds.origin.y;

    // Get the duration of the animation.
    NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration;
    [animationDurationValue getValue:&animationDuration];

    // Animate the resize of the text view's frame in sync with the keyboard's appearance.
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:animationDuration];

    textView.frame = newTextViewFrame;

    [UIView commitAnimations];
}

- (void)keyboardWillHide:(NSNotification *)notification {

    NSDictionary* userInfo = [notification userInfo];

    /*
     Restore the size of the text view (fill self's view).
     Animate the resize so that it's in sync with the disappearance of the keyboard.
     */
    NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration;
    [animationDurationValue getValue:&animationDuration];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:animationDuration];

    textView.frame = self.view.bounds;

    [UIView commitAnimations];
}

注:若在同一視窗中有兩個UITextField,當第一個UITextField成為First Responser時,開始顯示鍵盤並接收到UIKeyboardWillShowNotification,UIKeyboardDidShowNotification通知,當First Responser轉移到第二個UITextField時,鍵盤會一直顯示,此時不會收到WillShow和DidShow的通知。

四.使用inputAccessoryView與inputView定製輸入檢視

inputAccessoryView inputView屬性在 UIResponder中定義,為readonly的屬性,但在UITextFiled UITextView中重新定義為了readwrite的屬性,可以由使用者賦值。若 inputView的不為nil,則當文字檢視成為first responder時,不會顯示系統鍵盤,而是顯示自定義的inputView;若inputAccessoryView
為nil,則inputAccessoryView會顯示在系統鍵盤或定製inputView的上方。當使用inputView時,仍然會有WillShow,DidShow,WillHide,DidHide的鍵盤通知,通知中的BeginFrame與EndFrame為系統鍵盤(或inputView)與inputAccessoryView一起的frame。

自定義inputAccessoryView非常常見,如編輯簡訊時的輸入框


Web頁面輸入鍵盤


新浪微博評論介面

若想在輸入時不使用系統鍵盤,而使用自定義的鍵盤,則可以設定inputView,如隨手記中的金額輸入時的鍵盤

若不想使用鍵盤輸入,想從UIPickerView或UIDatePicker中選擇,可設定inputView為對應的Picker檢視,如圖

在標準檢視中只有UITextField和UITextView將inputView和inputAccessoryView重新定義為了readwrite型別,若想在自定義檢視中使用,需要在自定義檢視中重新定義inputView和inputAccessoryView屬性。見Input Views and Input Accessory Views