Question

This question already has an answer here:

I'd like to add a Done button to the iPhone number pad keyboard. There's even a handy space at the bottom left for just such a button.

Previously, I was using a similar trick to those described in Question 584538 and Luzian Scherrer's excellent blog post, but that stopped working in iOS 4. I can do it by creating a custom inputView, but I'd prefer to extend Apple's keyboard instead of writing my own.

Is there a new way to add a view to the standard keyboard? Has someone published an OSS inputView for this? Is there another way?

Was it helpful?

Solution 3

The technique described in Luzian Scherrer's blog post does work in iOS 4.0.

My code to add the button to the keyboard was failing because it was being called from the textFieldDidBeginEditing: delegate method, which (in 4.0) is called before the keyboard window's subviews are created. I fixed the problem by calling my code when UIKeyboardWillShowNotification is observed, which happens late enough.

OTHER TIPS

You can add inputAccessoryView with 'Apply' and 'Cancel' buttons, and dismiss the number pad with then.

inputAccessoryView

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];

    numberToolbar.items = [NSArray arrayWithObjects:
       [[UIBarButtonItem alloc]initWithTitle:@"Cancel" style:UIBarButtonItemStyleBordered target:self action:@selector(cancelNumberPad)],
       [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
       [[UIBarButtonItem alloc]initWithTitle:@"Apply" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)],
       nil];

    numberTextField.inputAccessoryView = numberToolbar;
}

-(void)cancelNumberPad{
    [numberTextField resignFirstResponder];
    numberTextField.text = @"";
}

-(void)doneWithNumberPad{
    NSString *numberFromTheKeyboard = numberTextField.text;
    [numberTextField resignFirstResponder];
}

I got this working. See the code here: http://gist.github.com/454844

There were two issues:

  1. UIKeyboardWillShowNotification is sent before the keyboard view exists, but it you schedule your code to run on the next run loop pass, they do exist. So you don't have to bother with DidShow which is visually less pleasing.

  2. On iOS 4 the UIKeyboard view was elsewhere in the view hierarchy.

I refactored the code and put it on github.

https://github.com/dazuiba/dz-numberpad-done-helper

I have submitted this to Apple as a bug. Interface Builder allows the developer to specify a Return Key type for a keyboard type of Number Pad. Bug number 8759674.

Apple followed up by saying that this issue has been previously logged as Bug ID# 5885964 and they closed 8759674.

You may use this keyboard notify code for making done button on number keypad.You have to just download done.png image at your end.

In .h file

  {     //Keyboard Hide
UIImage *numberPadDoneImageNormal;
UIImage *numberPadDoneImageHighlighted;
UIButton *numberPadDoneButton;
}

@property (nonatomic, retain) UIImage *numberPadDoneImageNormal;
@property (nonatomic, retain) UIImage *numberPadDoneImageHighlighted;
@property (nonatomic, retain) UIButton *numberPadDoneButton;

- (IBAction)numberPadDoneButton:(id)sender;

In .m file

@synthesize numberPadDoneImageNormal;
@synthesize numberPadDoneImageHighlighted;
@synthesize numberPadDoneButton;

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
if ([super initWithNibName:nibName bundle:nibBundle] == nil)
    return nil;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.0) {
    self.numberPadDoneImageNormal = [UIImage imageNamed:@"NumberDone.png"];
    self.numberPadDoneImageHighlighted = [UIImage imageNamed:@"NumberDone.png"];
} else {        
    self.numberPadDoneImageNormal = [UIImage imageNamed:@"NumberDone.png"];
    self.numberPadDoneImageHighlighted = [UIImage imageNamed:@"NumberDone.png"];
}        
return self;
}

- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];

// Add listener for keyboard display events
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardDidShow:) 
                                                 name:UIKeyboardDidShowNotification 
                                               object:nil];     
} else {
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:nil];
}

// Add listener for all text fields starting to be edited
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(textFieldDidBeginEditing:)
                                             name:UITextFieldTextDidBeginEditingNotification 
                                           object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
    [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                    name:UIKeyboardDidShowNotification 
                                                  object:nil];      
} else {
    [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                    name:UIKeyboardWillShowNotification 
                                                  object:nil];
}
[[NSNotificationCenter defaultCenter] removeObserver:self 
                                                name:UITextFieldTextDidBeginEditingNotification 
                                              object:nil];
[super viewWillDisappear:animated];
}

- (UIView *)findFirstResponderUnder:(UIView *)root {
if (root.isFirstResponder)
    return root;    
for (UIView *subView in root.subviews) {
    UIView *firstResponder = [self findFirstResponderUnder:subView];        
    if (firstResponder != nil)
        return firstResponder;
}
return nil;
}

- (UITextField *)findFirstResponderTextField {
UIResponder *firstResponder = [self findFirstResponderUnder:[self.view window]];
if (![firstResponder isKindOfClass:[UITextField class]])
    return nil;
return (UITextField *)firstResponder;
}

- (void)updateKeyboardButtonFor:(UITextField *)textField {

// Remove any previous button
[self.numberPadDoneButton removeFromSuperview];
self.numberPadDoneButton = nil;

// Does the text field use a number pad?
if (textField.keyboardType != UIKeyboardTypeNumberPad)
    return;

// If there's no keyboard yet, don't do anything
if ([[[UIApplication sharedApplication] windows] count] < 2)
    return;
UIWindow *keyboardWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];

// Create new custom button
self.numberPadDoneButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.numberPadDoneButton.frame = CGRectMake(0, 163, 106, 53);
self.numberPadDoneButton.adjustsImageWhenHighlighted = FALSE;
[self.numberPadDoneButton setTitle:@"Return" forState:UIControlStateNormal];
[self.numberPadDoneButton setFont:[UIFont boldSystemFontOfSize:18]];
[self.numberPadDoneButton setTitleColor:[UIColor colorWithRed:77.0f/255.0f green:84.0f/255.0f blue:98.0f/255.0f alpha:1.0] forState:UIControlStateNormal];  

[self.numberPadDoneButton setImage:self.numberPadDoneImageNormal forState:UIControlStateNormal];
[self.numberPadDoneButton setImage:self.numberPadDoneImageHighlighted forState:UIControlStateHighlighted];
[self.numberPadDoneButton addTarget:self action:@selector(numberPadDoneButton:) forControlEvents:UIControlEventTouchUpInside];

// Locate keyboard view and add button
NSString *keyboardPrefix = [[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2 ? @"<UIPeripheralHost" : @"<UIKeyboard";
for (UIView *subView in keyboardWindow.subviews) {
    if ([[subView description] hasPrefix:keyboardPrefix]) {
        [subView addSubview:self.numberPadDoneButton];
        [self.numberPadDoneButton addTarget:self action:@selector(numberPadDoneButton:) forControlEvents:UIControlEventTouchUpInside];
        break;
    }
}
}

- (void)textFieldDidBeginEditing:(NSNotification *)note {
[self updateKeyboardButtonFor:[note object]];
}

- (void)keyboardWillShow:(NSNotification *)note {
[self updateKeyboardButtonFor:[self findFirstResponderTextField]];
}

- (void)keyboardDidShow:(NSNotification *)note {
[self updateKeyboardButtonFor:[self findFirstResponderTextField]];
}

- (IBAction)numberPadDoneButton:(id)sender {
UITextField *textField = [self findFirstResponderTextField];
[textField resignFirstResponder];
}

- (void)dealloc {
[numberPadDoneImageNormal release];
[numberPadDoneImageHighlighted release];
[numberPadDoneButton release];
[super dealloc];
}

I've created a version to enable the horizontal version of the numpad... plug into the technique described in Luzian Scherrer's blog and add the two extra pngs (not included here), and the "isLandscape" boolean into "didRotateFromInterfaceOrientation" method..

    @interface AlarmController ()
    {
        CGRect doneButtnRectVert;
        CGRect doneButtnRectHorz;
        CGRect doneButtnRect;
        UIImage* DoneUpVert;
        UIImage* DoneDownVert;
        UIImage* DoneUpHorz;
        UIImage* DoneDownHorz;
        UIImage* DoneUp;
        UIImage* DoneDown;
        UIButton *oldDoneButton;
    }
    @end

    //---------------------------------------------------------------------------
    - (void)viewDidUnload
    {
    NSLog(@"viewDidUnload  AlarmController");
        [[NSNotificationCenter defaultCenter] removeObserver:self
                                      name:UIKeyboardDidShowNotification object:nil];

        [super viewDidUnload];
    }

    //---------------------------------------------------------------------------
    - (void)addButtonToKeyboard
    {
    NSLog(@"addButtonToKeyboard  AlarmController");
        if (isLandscape)
        {
            doneButtnRect = doneButtnRectHorz;
            DoneUp = DoneUpHorz;
            DoneDown = DoneDownHorz;
        } else {
            doneButtnRect = doneButtnRectVert;
            DoneUp = DoneUpVert;
            DoneDown = DoneDownVert;
        }

        UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
        doneButton.frame = doneButtnRect;
        doneButton.adjustsImageWhenHighlighted = NO;
        [doneButton setImage:DoneUp forState:UIControlStateNormal];
        [doneButton setImage:DoneDown forState:UIControlStateHighlighted];

        [doneButton addTarget:self action:@selector(done:) 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:@"<UIPeripheralHost"] == YES)
            {
                if (oldDoneButton) [oldDoneButton removeFromSuperview];
                [keyboard addSubview:doneButton];
            }
        }
        oldDoneButton = doneButton;
    }

    //---------------------------------------------------------------------------
    - (void)keyboardDidShow:(NSNotification *)note
    {
    NSLog(@"keyboardDidShow  AlarmController");
        [self addButtonToKeyboard];
    }

    #pragma mark -
    #pragma mark meaty area...

//---------------------------------------------------------------------------
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSLog(@"textFieldDidEndEditing AlarmController");
    oldDoneButton = nil;
}

    //---------------------------------------------------------------------------
    - (void)viewDidLoad
    {
    NSLog(@"viewDidLoad  AlarmController");
        [super viewDidLoad];
        doneButtnRectVert = CGRectMake(0, 163, 106, 53);
        doneButtnRectHorz = CGRectMake(0, 122, 159, 40);
        DoneUpVert = [UIImage imageNamed:@"DoneUp3.png"];
        DoneDownVert = [UIImage imageNamed:@"DoneDown3.png"];
        DoneUpHorz = [UIImage imageNamed:@"DoneUpHor.png"];
        DoneDownHorz = [UIImage imageNamed:@"DoneDnHor.png"];

        doneButtnRect = doneButtnRectVert;
        DoneUp = DoneUpVert;
        DoneDown = DoneDownVert;
        oldDoneButton = nil;

        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector(keyboardDidShow:) 
                                                     name:UIKeyboardDidShowNotification object:nil];        
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top