Reputation: 5817
Ugh ok my final post for this topic..I've narrowed it down as far as I can, but I'll definitely need help to solve this. Since I'm using custom cells and embedded table views, I have to do the scrolling myself when the keyboard appears and hides some textfields (each cell has a textfield). That works great. However, if my table view is moved up so far, that some cells are hidden behind my header or behind the navigation controller bar, everything gets messed up as soon as I end the edit mode. Then the before hidden cells are immediately in their normal state and not indenting back. This looks quite nasty and I don't know how to solve it. If no cells get hidden, of course everything looks nice.
So I've looked in the docs and found prepareForReuse and I guess this could help. Any idea how to solve this? I would be so incredibly thankful if someone can give me the necessary hint...
I have a custom UITableViewCell with only this method:
- (void) setEditing:(BOOL)editing animated:(BOOL)animated{
[super setEditing:editing animated:animated];
if (editing){
self.title.hidden = NO;
self.titleLabel.hidden = YES;
self.iconButton.hidden = NO;
self.icon.hidden = YES;
self.costs.hidden = YES;
self.disclosureIndicator.hidden = YES;
self.subcategories.hidden = YES;
} else if (!editing){
self.title.hidden = YES;
self.titleLabel.text = self.title.text;
self.titleLabel.hidden = NO;
self.iconButton.hidden = YES;
self.icon.hidden = NO;
self.subcategories.hidden = NO;
self.costs.hidden = NO;
self.disclosureIndicator.hidden = NO;
}
}
Initialized here and reused:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Data model and cell setup
static NSString *CellIdentifier = @"MainCategoryCell";
MainCategoryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
MainCategory *mainCategory = [self.fetchedResultsController objectAtIndexPath:indexPath];
...
return cell;
}
Since I'm using embedded table views I have to do the scrolling of hidden textfields due to the keyboard myself:
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
//Has to be unregistered always, otherwise nav controllers down the line will call this method
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)keyboardWasShown:(NSNotification*)aNotification
{
//All table views are embedded in the parent view
//The parent view y is defined by the status and navigation bar, the height by the tab bar
CGRect viewRect = self.view.frame;
CGRect tableRect = self.tableView.frame;
//The keyboard size will be adjusted that the height is really only the height overlapping the table
NSDictionary* info = [aNotification userInfo];
CGSize kbOriginalSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGFloat effectiveKeyBoardHeight = kbOriginalSize.height - TABBARHEIGHT - (viewRect.size.height - tableRect.size.height - tableRect.origin.y); //the last origin property is important to find out if there is a header
CGSize kbSize = CGSizeMake(kbOriginalSize.width, effectiveKeyBoardHeight);
//Now the content insets will be adjusted for the calculated part of the keyboard overlapping the table
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// I've changed the apple code here! They use viewRect..in my app this doesn't make any sense, tableRect is key
tableRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(tableRect, self.activeField.frame.origin) ) {
[self.tableView scrollRectToVisible:self.activeField.frame animated:YES];
}
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
}
Upvotes: 2
Views: 1511
Reputation: 5817
Solved it...I've struggled with this for week and it the solution was just moving one line of code...:
My begin and end edit table:
- (IBAction) editTable:(id)sender
{
if(self.editing)
{
//Change to editing no
[super setEditing:NO animated:YES];
//resigns first responder for all textfields
[self.view endEditing:YES];
[self setEditing:NO animated:YES];
[self.tableView setEditing:NO animated:YES];
//Remove Done button and exchange it with edit button
[self.navigationItem.rightBarButtonItem setTitle:NSLocalizedString(@"Edit", nil)];
[self.navigationItem.rightBarButtonItem setStyle:UIBarButtonItemStylePlain];
self.navigationItem.leftBarButtonItem = nil;
[self.navigationItem setHidesBackButton:NO animated:YES];
[((AppDelegate *)[[UIApplication sharedApplication] delegate]) saveContext];
self.suspendAutomaticTrackingOfChangesInManagedObjectContext = NO;
} else {
//Change to editing mode
[super setEditing:YES animated:YES];
[self.tableView setEditing:YES animated:YES];
[self setEditing:YES animated:YES];
//Exchange the edit button with done button
[self.navigationItem.rightBarButtonItem setTitle:NSLocalizedString(@"Done", nil)];
[self.navigationItem.rightBarButtonItem setStyle:UIBarButtonItemStyleDone];
[self.navigationItem setHidesBackButton:YES animated:YES];
//And insert instead of the back button an add button
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addButtonAction:)];
[self.navigationItem setLeftBarButtonItem:addButton];
}
}
The key here is to have:
[self.tableView setEditing:NO animated:YES];
at the very bottom of ending the edit state! Before I had it in front of the resign responder for all cells and that was the error. Because the end editing which resigns the first responder for all cells triggers of course my keyboardWillBeHidden method. Then the table recognizes it needs two new cells, however if the table ended the edit state already, the cells are in non-edit state. However if I switch this line of code to the end everything works out as it should! Hope this will help someone else sometime in the future..
Upvotes: 0
Reputation: 2768
I think the problem may be setting of tableview contentInset will not invoke tableView's prepareForReuse method or any other methods to invoke cellForRow which cause your hidden cell appear with strange state. So in keyboard hide method, configure all maybe show cells state, and then reloadData will help to show cell correctly.
Upvotes: 1
Reputation: 47729
Seems to me if you just do a reloadData everything should be cleaned up. (Remember, your dataSource should retain ALL of the state of each cell.)
Upvotes: 0