views:

301

answers:

1

Hi,

I must be missing something fundamental here. I have a UITableView inside of a NavigationViewController. When a table row is selected in the UITableView (using tableView:didSelectRowAtIndexPath:) I call pushViewController to display a different view controller. The new view controller appears correctly, but when I pop that view controller and return the UITableView is resized as if the keyboard was being displayed. I need to find a way to have the keyboard hide before I push the view controller so that the frame is restored correctly. If I comment out the code to push the view controller then the keyboard hides correctly and the frame resizes correctly.

The code I use to show the keyboard is as follows:

- (void) keyboardDidShowNotification:(NSNotification *)inNotification {
    NSLog(@"Keyboard Show");
    if (keyboardVisible) return;
    // We now resize the view accordingly to accomodate the keyboard being visible
    keyboardVisible = YES;

    CGRect bounds = [[[inNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    bounds = [self.view convertRect:bounds fromView:nil];   

    CGRect tableFrame = tableViewNewEntry.frame;
    tableFrame.size.height -= bounds.size.height; // subtract the keyboard height
    if (self.tabBarController != nil) {
        tableFrame.size.height += 48; // add the tab bar height
    }

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(shrinkDidEnd:finished:contextInfo:)];
    tableViewNewEntry.frame = tableFrame;
    [UIView commitAnimations];
}

The keyboard is hidden using:

- (void) keyboardWillHideNotification:(NSNotification *)inNotification {
    if (!keyboardVisible) return;
    NSLog(@"Keyboard Hide");
    keyboardVisible = FALSE;

    CGRect bounds = [[[inNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    bounds = [self.view convertRect:bounds fromView:nil];

    CGRect tableFrame = tableViewNewEntry.frame;
    tableFrame.size.height += bounds.size.height; // add the keyboard height
    if (self.tabBarController != nil) {
        tableFrame.size.height -= 48; // subtract the tab bar height
    }
    tableViewNewEntry.frame = tableFrame;   

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(_shrinkDidEnd:finished:contextInfo:)];
    tableViewNewEntry.frame = tableFrame;    
    [UIView commitAnimations];

    [tableViewNewEntry scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    NSLog(@"Keyboard Hide Finished");
}

I trigger the keyboard being hidden by resigning first responser for any control that is the first responder in ViewWillDisappear. I have added NSLog statements and see things happening in the log file as follows:

Show Keyboard
ViewWillDisappear: Hiding Keyboard
Hide Keyboard
Keyboard Hide Finished
PushViewController (an NSLog entry at the point I push the new view controller)

From this trace, I can see things happening in the right order, but It seems like when the view controller is pushed that the keyboard hide code does not execute properly.

Any ideas would be really appreciated. I have been banging my head against the keyboard for a while trying to find out what I am doing wrong.

-- Added didSelectRowAtIndexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    switch (indexPath.section) {
        case 0: // Required Info
                // removed to simplify
        case 1: // Optional Info
            switch (indexPath.row) {
                case 0:
                    [self showTextDetailPicker: @"Enter a description" 
                                           tag: tDescriptionPicker
                                  sourceTarget: self.newRecord
                                   fieldSource: @selector(description)]; 

                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }

}



- (void) showTextDetailPicker: (NSString*) titleText tag:(int)tagID sourceTarget:(NSObject*)target fieldSource:(SEL)selector{

    FieldEditorViewController *fe = [[FieldEditorViewController alloc] init];
    fe.titleText = titleText; 
    fe.fieldText = [target performSelector: selector];
    fe.tag = tagID;

    // Replace default back button with one that just says 'Back'
    UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] 
                                      initWithTitle:@"Back" 
                                      style:UIButtonTypeInfoLight
                                      target:nil action:nil];
    [[self navigationItem] setBackBarButtonItem: newBackButton];
    [newBackButton release];

    [fe setDelegate: self];
    [self.navigationController pushViewController:fe animated:YES];
    [fe release];   
}
+2  A: 

Right before you push your view controller, find the first responder and call resign. Use the category from this SO post to see how to find the first responder recursively (not sure if you're already doing this).

- (void)tableView:(UITableView *)tableView 
          didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIView *fp = [[self view] findFirstResponder];

    [fp resignFirstResponder];

    // Push new view controller here.
    NextViewController *controller = [[NextViewController alloc] init];
    [[self navigationController] pushViewController:controller animated:YES];
    [controller release], controller = nil;
}

The other thing to keep in mind is that your table view is getting resized automatically because your root view controller is derived from UITableViewController (or so it seems). If you make your root view controller a regular UIViewController that contains a UITableView, you can manipulate the frame of the table view manually more easily--at least that's been my experience.

Matt Long
Thanks for the response. I am already using the a category on UIView to find and resign the first responder. I am also using a regular UIViewController and resizing just the tableview when the keyboard is shown and hidden.
Pete
Hmmm. Sorry about that. Thought for sure that was the issue. How about just doing your table view resize in the -viewWillAppear? You could check its current size first to see if it needs resized or just brute force it and resize whenever the view is about to appear?
Matt Long