為UIKeyboardTypeNumberPad增加自定義按鍵


在 iPhone 上面開發應用程式時, 在使用輸入鍵盤時, 或多或少都會遇到客制化鍵盤的問題, 這邊筆者以
簡單的數字鍵盤來示範客制化的動作. 這部份我想網路上已經有不少 sample code , 但大部份基本上都是
以 SDK 3.x 的版本去實作, 以"特定寫法"來實作客制化在 iOS4 會有問題, 這部份稍候會提到兩版本的差異.

上述看到的例子是 UIKeyboardTypeNumberPad 搭配 "Done" 的圖示所組合而成的. 在開
始介紹如何實作之前, 先稍微提一下網路上查到的一些範例寫法. 因為 SDK 升版之
後在架構上有做了些修改, 所以導致行為上的不正確. 以下面這例子為例, 它可以正
常的在 iOS4 之前的版本運行, 但在 iOS4 上卻會有看不到上面 "Done" 圖示的問題.

- ( void )loadView{
    ...
     textFieldContent . delegate  =  self ;
     textFieldContent . placeholder  =  @"press me" ;
     textFieldContent . keyboardType  =  UIKeyboardTypeNumberPad ;
     textFieldContent . returnKeyType  =  UIReturnKeyDone ;
    [ self . view   addSubview : textFieldContent ];
    [ textFieldContent   release ];
    
    [[ NSNotificationCenter   defaultCenter addObserver : self  
                                     selector : @selector ( keyboardWillShow :) 
                                         name : UIKeyboardWillShowNotification  
                                       object : nil ];
    
}

- ( void )keyboardWillShowOnDelay:( NSNotification  *)notification{
     UIButton  *doneButton = [ UIButton   buttonWithType : UIButtonTypeCustom ];
    doneButton. frame  =  CGRectMake ( 0 163 106 53 );
    doneButton. adjustsImageWhenHighlighted  =  NO ;
    [doneButton  setImage :[ UIImage   imageNamed : @"DoneUp.png" forState : UIControlStateNormal ];
    [doneButton  setImage :[ UIImage   imageNamed : @"DoneDown.png" forState : UIControlStateHighlighted ];
    [doneButton  addTarget : self   action : @selector ( doneButton :)  forControlEvents : UIControlEventTouchUpInside ];
    
     UIWindow * tempWindow = [[[ UIApplication   sharedApplication windows objectAtIndex : 1 ];
     UIView * keyboard;
     for ( int  i= 0 ; i<[tempWindow. subviews   count ]; i++) {
        keyboard = [tempWindow. subviews   objectAtIndex :i];
         if ([[keyboard  description hasPrefix : @"<UIKeyboard" ] ==  YES )
            [keyboard  addSubview :doneButton];
    }
}


上述這段代碼主要原理是透過跟 OS 註冊 keyboard 相關的 notification, 並在顯示
keyboard 時, 在 keyboard view 上添加所需要的特定 UIView, 簡單流程大致如下
1. 註冊 UIKeyboardWillShowNotification : 當 keyboard 要秀時, OS 就會呼叫
    keyboardWillShow
2.  當被 keyboardWillShow 叫用時, 搜尋屬於 keyboard 的 view
   if([[keyboard descriptionhasPrefix:@"<UIKeyboard"] == YES)
3. 當找到所需要的 view 時, 再將需要的 view 加入即可
   [keyboard addSubview:doneButton];
上面就是一個 customized keyboard 的簡單實作流程. 但是為什麼這段 code 會無法
在 iOS4 上正確執行呢? 問題點主要出在上述的第 2 個步驟.
在舊的 SDK 中, 當 UIKeyboardWillShowNotification 事件發生且叫用 keyboardWillShow 
時, 此時的 keyboard view 已經被添加到 windows 裡了, 但是在 iOS4 的世界中, 相同
情況發生時, keyboard view 卻會在下個 event loop 裡才會被添加到 windows 中, 也
就是因為如此, 所以上述
[[[UIApplication sharedApplicationwindowsobjectAtIndex:1];
會找不到 keyboard view. 除了這原因以外, 還有另一個重要的差異性, 第 2 步驟所比
對的 @"<UIKeyboard" 字串在 iOS4 中也被修正過, 它被藏在 @"<UIPeripheralHostView"

裡.

針對這兩點, 所以將只要將之修正即可正常的在 iOS4 上執行
1. keyboard view
   既然知道是 keyboard view 會在下個 event loop 才會被放到 windows 裡, 所以我們
   可以透過下面方式將 keyboardWillShow 延遲叫用
   [self performSelector:@selector(keyboardWillShow:) withObject:nil afterDelay:0];
2. 修正比對 @"<UIKeyboard" 的方式

   if ([[possibleKeyboard  descriptionhasPrefix: @"<UIPeripheralHostView"]) 
       possibleKeyboard = [[possibleKeyboard  subviewsobjectAtIndex: 0];
 
   if ([[possibleKeyboard  descriptionhasPrefix: @"<UIKeyboard"])  
   {
       foundKeyboard = possibleKeyboard;
        break;
   }                
經過上述兩個修正之後的 code 大概會如下 :
    [[ NSNotificationCenter  defaultCenter addObserver : self  
                     selector: @selector( keyboardWillShowOnDelay:) 
                         name: UIKeyboardWillShowNotification 
                       object: nil];
 
- ( void)keyboardWillShowOnDelay:( NSNotification *)notification
{
    [ self  performSelector : @selector ( keyboardWillShow :) withObject : nil  afterDelay : 0 ]; 
}
 
- ( void)keyboardWillShow:( NSNotification *)notification
{    
     UIView *foundKeyboard =  nil;
    
     UIWindow *keyboardWindow =  nil;
     for ( UIWindow *testWindow  in [[ UIApplication  sharedApplicationwindows]) 
    {
         if (![[testWindow  classisEqual:[ UIWindow  class]]) 
        {
            keyboardWindow = testWindow;
             break;
        }
    }
     if (!keyboardWindow)  return;
    
     for ( UIView *possibleKeyboard  in [keyboardWindow  subviews]) 
    {            
         //iOS3
         if ([[possibleKeyboard  descriptionhasPrefix: @"<UIKeyboard"]) 
        {
            foundKeyboard = possibleKeyboard;
             break;
        }
         else
        {
            // iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
             if ([[possibleKeyboard  descriptionhasPrefix: @"<UIPeripheralHostView"]) 
            {
                possibleKeyboard = [[possibleKeyboard  subviewsobjectAtIndex: 0];
            }                                                                                
            
             if ([[possibleKeyboard  descriptionhasPrefix: @"<UIKeyboard"]) 
            {
                foundKeyboard = possibleKeyboard;
                 break;
            }                
        }            
    }
    
     if (foundKeyboard) 
    {
        // create custom button
         UIButton  *doneButton = [ UIButton  buttonWithType :UIButtonTypeCustom ];
        doneButton. frame =  CGRectMake( 016310653);
        doneButton.adjustsImageWhenHighlighted  =  NO ;
        [doneButton setImage :[ UIImage  imageNamed : @"DoneUp.png" forState :UIControlStateNormal ];
        [doneButton setImage :[ UIImage  imageNamed : @"DoneDown.png" forState :UIControlStateHighlighted ];
        [doneButton addTarget : self  action : @selector ( doneButton :) forControlEvents :UIControlEventTouchUpInside ];
        
        [foundKeyboard  addSubview:doneButton];
    }
}

 

 

 

 

 

 

If you have ever written an iPhone app that requires numeric input,then you surely know about the UIKeyboardTypeNumberPad. And if you haveever used that flavor of the iPhone's keyboard, then you surely knowthat it lacks one very important feature: The UIKeyboardTypeNumberPaddoes not have a "return" key.
In fact every other keyboard type (except for the pretty similarUIKeyboardTypePhonePad) does offer the possibility to be dismissed bysetting the returnKeyType property of the correspondingUITextInputTraits implementor. So how does one achieve the same effectwith the number pad? We have found a workround!
When looking at the number pad, you'll notice that there is anunused space on its bottom left. That's where we are going to plug inour custom "return" key.


To make it short: take a screenshot, cut out the whole backspacekey, flip it horizotally, clear its backspace symbol in Photoshop andoverlay it with the text that we want on our “return” key. We’ve chosento label it “DONE”. Now we have the image for our custombutton’s UIControlStateNormal. Repeat the whole procedure (with atouched backspace key when taking the screenshot) to get a second imagefor our button’s UIControlStateHighlighted. Here’s the result:
   

Now back to coding. First we need to know when the number pad isgoing to be slided up on the screen so we can plug in our custom buttonbefore that happens. Luckily there’s a notification for exactly thatpurpose, and registering for it is as easy as:
 
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(keyboardWillShow:) 
                                             name:UIKeyboardWillShowNotification 
                                           object:nil];
 [/pre]Don't forget to remove the observer from the notification center in the appropriate place once you're done with the whole thing:
 
[[NSNotificationCenter defaultCenter] removeObserver:self];[/pre]Now we’re getting to the heart of it. All we have to do in thekeyboardWillShow method is to locate the keyboard view and add ourbutton to it. The keyboard view is part of a second UIWindow of ourapplication as others have already figured out (see this thread).So we take a reference to that window (it will be the second window inmost cases, so objectAtIndex:1 in the code below is fine), traverse itsview hierarchy until we find the keyboard and add the button to itslower left:
 
(void)keyboardWillShow:(NSNotification *)note {  
    // create custom button
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    doneButton.frame = CGRectMake(016310653);
    doneButton.adjustsImageWhenHighlighted = NO;
    [doneButton setImage:[UIImage imageNamed:@"DoneUp.png"] forState:UIControlStateNormal];
    [doneButton setImage:[UIImage imageNamed:@"DoneDown.png"] forState:UIControlStateHighlighted];
    [doneButton addTarget:self action:@selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
 
    // locate keyboard view
    UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    UIView* keyboard;
    for(int i=0; i<[tempWindow.subviews count]; i++) {
        keyboard = [tempWindow.subviews objectAtIndex:i];
        // keyboard view found; add the custom button to it
        if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
            [keyboard addSubview:doneButton];
    }
}[/pre]Voilà, that’s it! The empty space for our button starts atcoordinate (0, 163) and has the dimensions (106, 53). The doneButtonmethod has to be written now of course, but that’s not hard any more.Just make sure that you call resignFirstResponder on the text fieldthat is being edited to have the keyboard slide down.

 

 

 

 

有一種思路叫寄生...

我相信是懶人推動了世界的發展,既然iphone有了自己的軟件盤,我們什么還要自己實現其功能呢。
so,只要寄生在上面就行了。

感謝alan轉載的文章給的靈感。
http://www.cocoachina.com/bbs/read.php?tid-3999.html

思路:
1.用靜態方法找到應用程序當前view(window)中的UIKeyboard的view
2.在 鍵盤的view上帖上自己的view,(精彩了,這個自己的view就是你自己 鍵盤,任意發揮,什么類型 鍵盤都可以做了)
3.根據需要調整系統 鍵盤的大小以滿足你想要的尺寸
4.給自己的鍵盤view上的button添加方法,實現功能

主要代碼:
添加自身類為 鍵盤事件的觀察者

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];

核心思路代碼:
- (void)keyboardWillShow:(NSNotification *)note
{
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];//知識點
for(int i=0; i<[tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
{
[keyboard setFrame:CGRectMake(0, 460, 320, 345)];
[self congfigKeypad];

[keyboard addSubview:keyPadView1];

}
}
}

比如配置方法可以是這樣:
-(void)congfigKeypad
{
SearBtn *one = [[SearBtn alloc] initWithFrame:CGRectMake(81, 3, kNumPadW, kNumPadH) index:1 ContextString:@"1" type:kNumPadType];
[one setImage:[UIImage imageNamed:@"1.png"] forState:UIControlStateNormal];
[one addTarget:self action:@selector(buttonClickAtIndex:) forControlEvents:UIControlEventTouchUpInside];
//......略
}

添加NSMutalbeString作為文本域字串的容器,點擊button后append的button對應的字串。
- (void)buttonClickAtIndex:(id)sender
{
SearBtn *btnItem = (SearBtn*)sender;
NSString *str = btnItem->btnText;
[s_text appendString:str];
[sBar setText:s_text];
}


再實現一個deleteChar的方法作為退格鍵
思路:
if ([s_text length] > 0)
{
NSRange rang;
rang.location = [s_text length] - 1;
rang.length = 1;
[s_text deleteCharactersInRange:rang];
}


現在點擊各種文本域,應該就可以現實自己的 鍵盤了。

繼續優化
用textfield的代理方法控制 鍵盤的字串類型,長度,和響應消失
[ 此帖被evangel在2009-12-17 22:32重新編輯 ]
圖片:圖片 1.png 

圖片:圖片 2.png 

  

Q:如果是通過[lang=objc][/lang]來顯示代碼的話,就不能再編輯了,不然都是亂碼……
A :也可以,要先把代碼去掉提交一次,然后再加上代碼修改再提交一次……

隱藏鍵盤

UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    UIView* keyboard;
    for(int i=0; i<[tempWindow.subviews count]; i++) {
        keyboard = [tempWindow.subviews objectAtIndex:i];
        // keyboard view found; add the custom button to it
        if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
            //[keyboard addSubview:keyboardView];
            keyboard.hidden=YES;
    }

還能隱藏鍵盤,使用自己的view載入動畫和控制位置,也不需要擔心背景是否會顯示出默認鍵盤!!lucky!!

 
多個頁面應該不會有問題,切換頁面時候鍵盤就消失了。

同一個頁面的時候:
1。設置鍵的view為實例變量

2。給有自定義鍵盤的那個textfield添加delegate方法:- (void)textFieldDidEndEditing:(UITextField *)tf;
在這個方法里[myKeyPad removeFromSuperview];

3。在- (void)keyboardWillShow:(NSNotification *)note;里判斷有自定鍵盤的textfield為firstResponder時候,再add鍵盤的view。
if([textField isFirstResponder])  [myKeyPad addSubview:doneButton];

當然還有很多別的方法

 

重新回復一下這個帖子,因為時間過去大半年了,我用SDK4.0,無法按照樓主的代碼直接實現,而是做了一點點的修改才能實現。大家誰有時間幫忙用最新SDK測試一下,看看是不是如此。

問題與修改1
原帖中用UIKeyboardWillShowNotification,tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1] 的subview數目為0!
我改UIKeyboardDidShowNotification,一切正常。

問題與修改2
原帖中用了字符串@"<UIKeyboard"來檢測鍵盤的view,在我這不管用。
我改用了@"<UIPeripheralHostView"

結果:

修改后,在SDK4.0的模擬器和真機上測試ok!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM