3
votes

I'm using the method described by Josh in this question to add a toolbar to the top of the iPhone's keyboard. Basically, the idea is:

  • Add the view controller as an observer for the notifications UIKeyboardWillShowNotification and UIKeyboardWillHideNotification in its initialization method
  • Whenever those notifications are posted, animate a toolbar onto/off of the screen along with the keyboard

I also have multiple UITextFields on the screen, all of which become the first responder when selected for editing and resign first responder when editing is complete (either the user taps another text field, off any text field, or presses "Done" on the keyboard - I have textFieldShouldReturn: overridden to resignFirstResponder).

I'm having a problem, though, since the notifications are being posted every time I switch between text fields. For example, if a user is editing text field A, then finishes with it and taps text field B, A resigns first responder and B becomes first responder. However, this also posts both the "will show" and "will hide" notifications to my view controller.

The end result of all this is that while the toolbar appears with the keyboard for the first text field, and disappears with the keyboard for the last text field, it appears to slide into and back out of the keyboard every time the user switches between text fields.

Is there a way to only respond to the "will {show,hide}" notifications if the keyboard is actually going to show or hide? Put another way, how can I ignore notifications that will not result in a change in the keyboard's visible state?

2

2 Answers

4
votes

You need to make a BOOL ivar to keep track of whether or not the keyboard is already visible, so you'll make good use of all of the UITextField delegate methods :) Toolbars with multiple text fields can be tricky, but you're very close!

4
votes

To follow up on Reed's answer: I wound up using the following implementation. It uses a BOOL to track whether the controller is between a textFieldShouldBeginEditing: and textFieldDidBeginEditing: message, as well as an ivar to track the currently editing text field.

The implementation assumes the interface has the following, with appropriate properties and @synthesize markers. MyKeyboardToolbar is a subclass of UIToolbar with a customized initializer to create its own buttons.

BOOL shouldBeginEditing;
UITextField *editingField;
MyKeyboardToolbar *keyboardBar;

And the code itself:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    // Give up first responder so the keyboard goes away
    [textField resignFirstResponder];

    return YES;
}

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    self.shouldBeginEditing = YES;
    return YES;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    self.shouldBeginEditing = NO;
    self.editingField = textField;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    // Do things here with the edited data (e.g. save it somewhere)

    return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    self.editingField = nil;
}

// These methods are added as the observers to the notification center
- (void)keyboardWillShow:(NSNotification *)notification {
    if(self.keyboardBar == nil) {
        // Create and show the keyboard toolbar
    }
}

- (void)keyboardWillHide:(NSNotification *)notification {
    if(![self shouldBeginEditing]) {
        // Animate the bar off the screen, if necessary

        // Remove and dispense of the bar entirely
        [self.keyboardBar removeFromSuperview];
        self.keyboardBar = nil;
    }
}

// This method's selector is given to the keyboard toolbar's Done button
- (void)didPressKeyboardBarDoneButton {
    [self.editingField resignFirstResponder];
}