5
votes

I am making an iOS application which required user to enter numeric values for multiple text fields. Under UITextField attributes, I have used

Keyboard = Decimal Pad

Return Key = Done

The keyboard is taking up the space and hiding the "Submit Form" Button.

Under the UIViewController.h file, I have written the following code for each UITextField, with event as Did end on Exit:

-(IBAction)dismissKeyboard:(id)sender;

Under the UIViewController.m file, I have written the following code for each UITextField:

-(IBAction)dismissKeyboard:(id)sender {

    [textField becomeFirstResponder];
    [textField resignFirstResponder];
}

When I open iOS simulator for Xcode 5, I do not get any DONE field on the on-screen keyboard. However, if I press RETURN key from my MacBook keyboard, the on-screen keyboard goes away.

How can I -

  • Display the DONE key on the iOS keyboard?
  • Dismiss the keyboard?
5
You only need the resignFirstResponder call in your dismissKeyboard method.Lev Landau
Actually, the reason he likely had to put both is that it really should only be [sender resignFirstResponder]; And you'll probably need to cast sender to a UITextView.wottle

5 Answers

8
votes

Since scroll view has been suggested, I will recommend another approach.

For each numeric input field, set an input accessory view - a toolbar - with a "Done" button in it. It will look like the bar above the keyboard in Safari. Once the user taps this Done button, close the keyboard like you normally do.

This is the simplest solution.

UIToolbar* toolbar = [UIToolbar new];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissKeyboard:)];
id space = [UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL];
toolbar.items = @[space, doneButton];

self.numericTextField1.inputAccessoryView = toolbar;
self.numericTextField2.inputAccessoryView = toolbar;
...
2
votes

In .h class, first declare a scroll view.

@property (strong, nonatomic) IBOutlet UIScrollView *scrRegistration;

In .m class,use these code

-(void)viewWillAppear:(BOOL)animated 
{
    UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard:)];
    [gesture setNumberOfTapsRequired:1];
    [gesture setNumberOfTouchesRequired:1];
    [self.scrRegistration addGestureRecognizer:gesture];
    [self.scrRegistration setContentSize:CGSizeMake(320, 354)];
    for (UIView *vw in [self.scrRegistration subviews]) {
        if([vw isKindOfClass:[UITextField class]]){
            UITextField *txtfld=(UITextField *)vw;
            txtfld.attributedPlaceholder = [[NSAttributedString alloc] initWithString:txtfld.placeholder attributes:@{NSForegroundColorAttributeName: [UIColor colorWithRed:8.0f/255.0f green:94.0f/255.0f blue:165.0f/255.0f alpha:1.0]}];
        }
    }
}

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    if(textField==DecimalKeyboard) {
        if([[UIScreen mainScreen] bounds].size.height>480) {
            [self.scrRegistration setContentOffset:CGPointMake(0, 110) animated:YES];
        } else {
            [self.scrRegistration setContentOffset:CGPointMake(0, 300) animated:YES];
        }
        UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
        numberToolbar.barStyle = UIBarStyleBlackTranslucent;
        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:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)],
                               nil];
        [numberToolbar sizeToFit];
        textField.inputAccessoryView = numberToolbar;
   }
}




-(void)hideKeyboard:(UITapGestureRecognizer *)tap 
{
    [DecimalKeyboard resignFirstResponder];
    [self.scrRegistration setContentOffset:CGPointMake(0, 0) animated:YES];
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView commitAnimations];
}



-(void)cancelNumberPad
{
    for (UIView *vw in [self.scrRegistration subviews]) {
        if([vw isKindOfClass:[UITextField class]]) {
            UITextField *txtfld=(UITextField *)vw;
            if ([txtfld isFirstResponder] == YES) {
                [txtfld resignFirstResponder];
            }
        }
    }

    [self.scrRegistration setContentOffset:CGPointMake(0, 0) animated:YES];
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView commitAnimations];
}



-(void)doneWithNumberPad
{
    [DecimalKeyboard resignFirstResponder];
    [self.scrRegistration setContentOffset:CGPointMake(0, 0) animated:YES];
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.35];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView commitAnimations];
}
1
votes

You might be better off simply putting the contents on screen into a scrollview, then resizing the view when the keyboard is present. That's typically the approach I take when I have an input form and it's very easy to implement. To do this, you can follow the instructions in this answer:

https://stackoverflow.com/a/16044603/3708242

First, make sure you register your viewController for the keyboard notifications (and remove the observers when the view is going away):

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

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

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

Here's the main part of the code. It assumes you have a view that takes up the whole screen. If that's not the case, you'll need to tweak the CGRects in the two methods below.:

- (void)keyboardWillShow:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        self.contentView.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
    } completion:nil];
}

- (void)keyboardWillHide:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        self.contentView.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
    } completion:nil];
}
1
votes

In case anyone else comes across this question when learning Swift, after a lot of failed attempts I finally had some success with this code in my ViewController, based on Leo Natan's answer above:

@IBOutlet var decimalField : UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    // ...

    addDoneButtonToKeyboard()

    // ...

    // Do any additional setup after loading the view, typically from a nib.
    refreshUI()
}

func addDoneButtonToKeyboard() {
    var doneButton:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "hideKeyboard")

    var space:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)

    var items = [AnyObject]()
    items.append(space)
    items.append(doneButton)

    toolbar.items = items

    decimalField.inputAccessoryView = toolbar
}

func hideKeyboard() {
    decimalField.resignFirstResponder()
}
0
votes

You should consider having the input form in a scroll view. This way the app can scroll the form so that the submit button becomes visible. Your users can also scroll up and down to see all the input.

To have a numerical keyboard with a done button you need to create a custom input view.

An alternative is to dismiss the keyboard on any tap outside the keyboard and the text fields, but the user experience would be awkward.