为iphone的数字键盘添加"return"key

UIKeyboardTypeNumberPad and the missing "return" key

WRITTEN BY LUZIAN SCHERRER ON 21 APRIL 2009.

If you have ever written an iPhone app that requires numeric input, then you surely know about the UIKeyboardTypeNumberPad. And if you have ever used that flavor of the iPhone's keyboard, then you surely know that it lacks one very important feature: The UIKeyboardTypeNumberPad does not have a "return" key.

UPDATE 17 June 2010

With the arrival of new iOS versions (like 3.2 for iPad and 4.0 for iPhone/iPod touch), some internals regarding our solution have seized working due to changes in the SDK on Apple's side (as some of our readers pointed out in the comments). Now we have updated our solution to also work with iOS versions > 3.1.3 (meaning specifically 3.2 and 4.0GM "golden master"). Please feel free to download the complete XCode project at the bottom of the article.
To keep it short, the behaviour of the keyboard has changed in versions > 3.1.3 in such a manner that it's no longer possible to add the button before the keyboard slides up. This means that the done button has to be added after the keyboard is put in place. This has been pointed out andexplained in more detail by one of our readers.

In that way, the new solution is not perfect. On the other hand, most users will not be aware of it anyway. We're looking into the matter in more detail when we find some spare time and maybe come up with a more sophisticated solution.

In fact every other keyboard type (except for the pretty similar UIKeyboardTypePhonePad) does offer the possibility to be dismissed by setting the returnKeyType property of the corresponding UITextInputTraits implementor. So how does one achieve the same effect with the number pad? We have found a workround!

When looking at the number pad, you'll notice that there is an unused space on its bottom left. That's where we are going to plug in our custom "return" key.

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

Now back to coding. First we need to know when the number pad is going to be slided up on the screen so we can plug in our custom button before that happens. Luckily there’s a notification for exactly that purpose, and registering for it is as easy as:

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

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];
 

Now we’re getting to the heart of it. All we have to do in the keyboardWillShow method is to locate the keyboard view and add our button to it. The keyboard view is part of a second UIWindow of our application as others have already figured out (see this thread). So we take a reference to that window (it will be the second window in most cases, so objectAtIndex:1 in the code below is fine), traverse its view hierarchy until we find the keyboard and add the button to its lower left:

 
- (void)keyboardWillShow:(NSNotification *)note {  
    // create custom button
    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];
 
    // 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];
    }
}
 

Voilà, that’s it! The empty space for our button starts at coordinate (0, 163) and has the dimensions (106, 53). The doneButton method has to be written now of course, but that’s not hard any more. Just make sure that you call resignFirstResponder on the text field that is being edited to have the keyboard slide down.

We’re “DONE”.

We have just discovered that the graphical design of the keyboard has slightly changed in the current iPhone OS 3.0 beta version. This means that the position and the image of our custom button will have to be adapted to that new style.

The whole thing can be downloaded as an Xcode project from us.
UPDATE: download 3.0 compatible Xcode project.
UPDATE 2010: download the newest version (runs on all "known" versions 2.0 - 4.0)

Comments (166)

+5
AppManiac's avatar

AppManiac· 208 weeks ago

You are my hero.
2 replies  · active 50 weeks ago
+2
Bernd's avatar

Bernd· 208 weeks ago

Thanks for the very neat idea! 
I found it to work better though with a textfield delegate instead of notification. This was because I had several textfields, both numbers and conventional text. 

Great Post! 
Bernd
2 replies  · active 195 weeks ago
+9
sdd's avatar

sdd· 208 weeks ago

Oh man, this iphone dev has not ceased to amaze me. This kind of hackery to get the most vital component of any keyboard ever? Oh dear. Oh dear! Why, apple, WHY?!!!!!!!
1 reply  · active 33 weeks ago
-1
kayhan's avatar

kayhan· 207 weeks ago

But what if we have a number and a default keyboard?
2 replies  · active 207 weeks ago
This is absolutely fantastic. Thank you so much for posting it!
-2
Barak's avatar

Barak· 206 weeks ago

Has anyone figured out what is needed to make this work on IPhone OS 3.0?
1 reply  · active 206 weeks ago
Here is a less awful for-loop. 

for (UIView *keyboard in tempWindow.subviews) { 
if ([[[keyboard class] name] hasPrefix:@"UIKeyboard"]) { 
[keyboard addSubview:doneButton]; 
break; 



Usually modifying a collection while fast-enumerating it will cause an exception to be thrown, but we can get away with it in this case because we immediately break out of the loop after the modification.
-1
Cormac's avatar

Cormac· 204 weeks ago

Luzian, thanks for posting this, it has been most helpful and does exactly what I need. However I have a small problem - everything works perfectly in the 3.0 simulator but the button images do not seem to display when running on OS 3.0 on the device, although the button still responds correctly to touch. Nothing strange appearing on the console. Any pointers would be extremely helpful...
1 reply  · active 204 weeks ago
-1
Doug's avatar

Doug· 199 weeks ago

Has anyone updated the image to work with OS 3.0? I would do it myself, but my Photoshop skills are lacking! :-)
-2
Harris's avatar

Harris· 198 weeks ago

Here's some up and down 'return' key images I made for OS 3.0. 
http://harrisrappaport.com/misc/ReturnUp.png 
http://harrisrappaport.com/misc/ReturnDown.png
We've updated this to make it 3.0 compatible. Just download the new Xcode project (link is in the article above). You'll find that both OS 2.x and 3.x are supported (the appropriate button style is automatically applied). 
This has been accomplished by altering the following two lines 

[doneButton setImage:[UIImage imageNamed:@"DoneUp.png"] forState:UIControlStateNormal]; 
[doneButton setImage:[UIImage imageNamed:@"DoneDown.png"] forState:UIControlStateHighlighted]; 

by 

if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"3"]) { 
[doneButton setImage:[UIImage imageNamed:@"DoneUp3.png"] forState:UIControlStateNormal]; 
[doneButton setImage:[UIImage imageNamed:@"DoneDown3.png"] forState:UIControlStateHighlighted]; 
} else { 
[doneButton setImage:[UIImage imageNamed:@"DoneUp.png"] forState:UIControlStateNormal]; 
[doneButton setImage:[UIImage imageNamed:@"DoneDown.png"] forState:UIControlStateHighlighted]; 
}
0
DuMe's avatar

DuMe· 196 weeks ago

I'm using this keyboard for two differents textfield and i need different action on done button. How can I identify the textfield i'm leaving? 
Thanks
2 replies  · active 195 weeks ago
+1
Charlie's avatar

Charlie· 195 weeks ago

sorry i'm sort of a noob and i need to do exactly this but with multiple textfields (some default keyboard some numberpad) .. would someone be so kind as to post the exact code needed to accommodate this.. i just played with it for an hour and couldn't get it to work..
-1
peter's avatar

peter· 194 weeks ago

Does anyone know if this could be an issue when getting the app approved by Apple? Do they frown upon people drawing on the keyboard? Has anyone had their app approved with this in place?
1 reply  · active 194 weeks ago
0
Chris's avatar

Chris· 194 weeks ago

When using this with other keyboard types, where would be the best place to remove the button subview? If the user clicks off the numpad and onto a normal textfield, how can I catch the loss of focus to remove the done button? Sorry, I'm pretty new to this environment.
4 replies  · active 132 weeks ago
Great Post, but I still have a problem - I am new at this so please bear with me. I have an application were I created customCells, with a textField for numeric input. Everything is loaded from a nib, not created dynamically like your example. Anyway, I was able to get the new Done button up and active, however when I press the done button - I execute the [self.valueLabel resignFirstResponder], but NOTHING happens, the Number Pad stays up. I tried setting self, Super etc... the message resignFirstResponder - did not help. Anybody have any ideas? How should the xib (File Owner, First Responder, textField) be set-up? Thanks For any help
4 replies  · active 163 weeks ago
-1
theDark's avatar

theDark· 188 weeks ago

i've always though (and continue to think) that apple is pretty stupid for giving users options for seemings random return-type buttons, like "Go" and "Route", while much MUCH more obvious and useful choices, like "Login" or "Save" are not available! 

this was a huge help! thank you very much!
0
Vince's avatar

Vince· 187 weeks ago

Has anyone gotten this to work in landscape mode? The code works great when in portrait mode, but when I turn the device sideways to landscape mode, the button does not appear and the number pad won't disappear.
As per the Bernd's comment above, to use this with multiple fields you need to trigger the code that adds the "Done" button using the UITextFieldDelegate protocol, instead of a NSNotification. 

Here's a snippet that adds the button using the textFieldDidBeginEditing method of the UITextFieldDelegate protocol. 

- (void) textFieldDidBeginEditing:(UITextField *)textField { 
if (textField == passwordValue) { 
// 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]; 



}
5 replies  · active 129 weeks ago
Good stuff. saved me from despair and using an inappropriate keyboard! 

Thanks for the post.
-1
João Cargas's avatar

João Cargas· 181 weeks ago

Hi, 
work perfectly, but i would like it work in landscape mode too when i rotate, but i can't, how i can do it? 
thanks
-1
João Cargas's avatar

João Cargas· 181 weeks ago

solve 
"doneButton.frame = CGRectMake(0, 123, 158,39);" 

I create other images, but they don't appear in device, but resign is ok and simulator all is ok
0
Yuri's avatar

Yuri· 181 weeks ago

Same thing here. The images only show on the simulator. But not on the device. Button still works fine on both though.
-2
mat's avatar

mat· 178 weeks ago

Hi, i'm new in iphone development, i've a question... 

i want to attach this feature to my nib file..but if i override viewLoad method (like in the folder project) my xib file doesn't appear, 
there is just a textFiled created in the viewLoad. 

Sorry for my bad english!!
-1
zefcan's avatar

zefcan· 178 weeks ago

Brilliant post, thanks for this!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值