How to add a 'Done' button to numpad keyboard in iOS

IosIphoneCocoa TouchUitextfieldUikit

Ios Problem Overview


So, the numpad keyboard doesn't come with a 'Done' or 'Next' button by default so I'd like to add one. In iOS 6 and below there were some tricks to add a button to the keyboard but they don't seem to be working in iOS 7.

First I subscribe to the keyboard showing notification

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

Then I try to add a button when the keyboard shows up:

- (void)keyboardWillShow:(NSNotification *)note 
{
    // create custom button
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem];
    doneButton.frame = CGRectMake(0, 50, 106, 53);
    doneButton.adjustsImageWhenHighlighted = NO;
    [doneButton setTitle:@"Done" forState:UIControlStateNormal];
    [doneButton addTarget:self action:@selector(dismissKeyboard) 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];
    }
}

But the for loop doesn't run because it doesn't find any subviews. Any suggestions? I couldn't find any solutions for iOS7 so is there a different way I'm supposed to be doing this?

Edit: Thanks for all the suggestions for toolbars guys but I'd rather not go down that route as I'm quite space poor (and it is kind of ugly).

Ios Solutions


Solution 1 - Ios

The much safer approach is to use a UIToolBar with Done Button as inputAccessoryView.


Sample Code :

UIToolbar *keyboardDoneButtonView = [[UIToolbar alloc] init];
[keyboardDoneButtonView sizeToFit];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done"
                                                               style:UIBarButtonItemStyleBordered target:self
                                                              action:@selector(doneClicked:)];
[keyboardDoneButtonView setItems:[NSArray arrayWithObjects:doneButton, nil]];
txtField.inputAccessoryView = keyboardDoneButtonView;

Your -doneClicked method should look like this :

- (IBAction)doneClicked:(id)sender
{
    NSLog(@"Done Clicked.");
    [self.view endEditing:YES];
}

Sample Code Swift:

let keyboardDoneButtonView = UIToolbar.init()
keyboardDoneButtonView.sizeToFit()
let doneButton = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.Done, 
                                                   target: self, 
                                                   action: Selector("doneClicked:")))    

keyboardDoneButtonView.items = [doneButton]
textFieldInput.inputAccessoryView = keyboardDoneButtonView

Your -doneClicked method should look like this :

func doneClicked(sender: AnyObject) {
  self.view.endEditing(true)
}

Solution 2 - Ios

Even easier way:

Swift 3.0 and above:

func addDoneButton() {
    let keyboardToolbar = UIToolbar()
    keyboardToolbar.sizeToFit()
    let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
        target: nil, action: nil)
    let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done,
        target: view, action: #selector(UIView.endEditing(_:)))
    keyboardToolbar.items = [flexBarButton, doneBarButton]
    textField.inputAccessoryView = keyboardToolbar
}

Swift 2.3 and below:

func addDoneButton() {
    let keyboardToolbar = UIToolbar()
    keyboardToolbar.sizeToFit()
    let flexBarButton = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace,
        target: nil, action: nil)
    let doneBarButton = UIBarButtonItem(barButtonSystemItem: .Done,
        target: view, action: #selector(UIView.endEditing(_:)))
    keyboardToolbar.items = [flexBarButton, doneBarButton]
    textField.inputAccessoryView = keyboardToolbar
}

Objective C:

- (void)addDoneButton {
    UIToolbar* keyboardToolbar = [[UIToolbar alloc] init];
    [keyboardToolbar sizeToFit];
    UIBarButtonItem *flexBarButton = [[UIBarButtonItem alloc]
    initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
    target:nil action:nil];
    UIBarButtonItem *doneBarButton = [[UIBarButtonItem alloc]
    initWithBarButtonSystemItem:UIBarButtonSystemItemDone
    target:self.view action:@selector(endEditing:)];
    keyboardToolbar.items = @[flexBarButton, doneBarButton];
    self.textField.inputAccessoryView = keyboardToolbar;
}

EDIT:

I've created a useful library called DCKit, which already have the toolbar out of the box:

Done toolbar above keyboard in iOS (with using DCKit library)

It also has many other cool features.

Solution 3 - Ios

This is a simple way of projecting a done button in iOS7 num-keypad. In the below delegate method of UITextField, add a notification for keyboard show.

-(void)textFieldDidBeginEditing:(UITextField *)textField {
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];
}

Now implement the method keyboardWillShow as below. Here we need to take extra care for iOS7.

- (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:@"doneButtonNormal.png"] forState:UIControlStateNormal];
    [doneButton setImage:[UIImage imageNamed:@"doneButtonPressed.png"] forState:UIControlStateHighlighted];
    [doneButton addTarget:self action:@selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
    
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
        dispatch_async(dispatch_get_main_queue(), ^{
            UIView *keyboardView = [[[[[UIApplication sharedApplication] windows] lastObject] subviews] firstObject];
            [doneButton setFrame:CGRectMake(0, keyboardView.frame.size.height - 53, 106, 53)];
            [keyboardView addSubview:doneButton];
            [keyboardView bringSubviewToFront:doneButton];
            
            [UIView animateWithDuration:[[note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]-.02
                                  delay:.0
                                options:[[note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]
                             animations:^{
                                 self.view.frame = CGRectOffset(self.view.frame, 0, 0);
                             } completion:nil];
        });
    } else {
        // locate keyboard view
        dispatch_async(dispatch_get_main_queue(), ^{
            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];
            }
        });
    }
}

Now add this macro to suitable header to detect the SYSTEM_VERSION

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

Solution 4 - Ios

Just building on answers above with the Swift version since I had to translate it:

@IBOutlet weak var numberTextField: UITextField!

override func viewDidLoad() {
    addDoneButtonTo(numberTextField)
}

// MARK: Done for numberTextField

private func addDoneButtonTo(textField: UITextField) {
    let flexBarButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
    let doneBarButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: "didTapDone:")
    let keyboardToolbar = UIToolbar()
    keyboardToolbar.sizeToFit()
    keyboardToolbar.items = [flexBarButton, doneBarButton]
    textField.inputAccessoryView = keyboardToolbar
}

func didTapDone(sender: AnyObject?) {
    numberTextField.endEditing(true)
}

Solution 5 - Ios

You can add a button to the keyboard's input accessory view

myTextField.inputAccessoryView =_inputView;

input accessory view is a view that comes over the keyboard always and dismiss with the [textfield resignFirstResponder]

put done over the input view and perform resign first responder of the textfields.

Solution 6 - Ios

  1. register the controller to the notification
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // Keyboard events
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}
  1. don't forget to remove the controller from the notification centre
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.view endEditing:YES];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
  1. implement keyboard notification handlers
- (void)keyboardWillShow:(NSNotification *)notification {

    // create custom button
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    doneButton.frame = CGRectMake(0, 107, 106, 53);
    [doneButton setTitle:@"Done" forState:UIControlStateNormal];
    [doneButton addTarget:self  action:@selector(doneButton:)forControlEvents:UIControlEventTouchUpInside];
 
   // save the reference to the button in order to use it in keyboardWillHide method
   self.donekeyBoardBtn = doneButton;

   // to my mind no need to search for subviews
   UIWindow *windowContainigKeyboard = [[[UIApplication sharedApplication] windows]  lastObject];
   [windowContainigKeyboard addSubview:self.donekeyBoardBtn];
   self.donekeyBoardBtn.frame = CGRectMake(0., CGRectGetHeight(w.frame) -  CGRectGetHeight(self.donekeyBoardBtn.frame), CGRectGetWidth(self.donekeyBoardBtn.frame), CGRectGetHeight(self.donekeyBoardBtn.frame));
}

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

    [self.donekeyBoardBtn removeFromSuperview];
}
  1. implement done button action
- (void)doneButton:(id)sender {
    // add needed implementation
    [self.view endEditing:YES]; 
}

Solution 7 - Ios

Just use

>yourTextField.inputAccessoryView

hope you help

Solution 8 - Ios

You do need to detect whether you are on a phone or iPad since the iPad implements a return key on the "number" pad

Solution 9 - Ios

Keyboard view could be found hasPrefix:@"UIKeyboard", the button can not be added as a subview. Here's my solution: enter link description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGeorge McKibbinView Question on Stackoverflow
Solution 1 - IosBhavinView Answer on Stackoverflow
Solution 2 - IosAndrey GordeevView Answer on Stackoverflow
Solution 3 - IosBalram TiwariView Answer on Stackoverflow
Solution 4 - IosArnaudView Answer on Stackoverflow
Solution 5 - IosHimanshu GuptaView Answer on Stackoverflow
Solution 6 - IosloloaView Answer on Stackoverflow
Solution 7 - IosalvarodouneView Answer on Stackoverflow
Solution 8 - Iosuser3288300View Answer on Stackoverflow
Solution 9 - IosanarchistView Answer on Stackoverflow