Thursday, April 7, 2016

How to prevent overflow of adjustable height tableview cell on delete

Leave a Comment

In a UITableView Controller, I have just added 'swipe to delete' by implementing tableView: commitEditingStyle: forRowAtIndexPath. Additionally, the rows can be selected to expand showing more content.

The undesired result after swiping:

enter image description here

The two lower rows remain in view after swiping until about about 0.5 seconds after the undelete animation completes.

A screenshot of IB:

enter image description here

The cell's contents have grown into the lower cell without it showing that it has been selected. (Selection causes the cell to increase height and give it a grayish background color.) This is occurring on every row in 2 similarly operating view controllers.

I have tried (without success) to intercept the 'selection' in several UITableViewDelegate methods, and cannot find out how to stop this from occurring. I have also tried setting the IB dynamic prototype cells to height: 85.

Looking for ideas on how to prevent this expansion from occurring.

EDIT

- (void)viewDidLoad {     ....     self.tableView.rowHeight = UITableViewAutomaticDimension;     self.tableView.estimatedRowHeight = kCellHeight;     .... }  #pragma mark - TableView delegate - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {     return [[self.fetchedResultsController sections] count]; }  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {     id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];     NSInteger *rows = (NSInteger *)[sectionInfo numberOfObjects];     if (!self.rowsInSection)         self.rowsInSection = rows;      if (rows > 0)         return [sectionInfo numberOfObjects];     else {         [tableView setSeparatorColor:[UIColor clearColor]];         [tableView setBounces:NO];         return 1;     } }  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {     NSString *identifier = self.rowsInSection > 0 ? @"numberIdentifier" : @"noNumbersIdentifier";      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];     if (self.rowsInSection > 0)         [self configureCell:cell atIndexPath:indexPath];     else         cell.selectionStyle = UITableViewCellSelectionStyleNone;      // [self.arrayOfIndexPaths addObject:indexPath];     return cell; }  - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {     NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];     if (selectedIndexPath) {         if (tableView.editing)             return 85.0;         else if (selectedIndexPath.row == indexPath.row)             return 185.0;     }      return 85.0; }  - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)path {     if (tableView.editing)         return nil;      //  If real rows exist, return the path, making row selectable     if (self.rowsInSection > 0)         return path;      //  Otherwise do not allow the row to be selected     return nil; }  - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {     id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][0];      if ([sectionInfo numberOfObjects] > 0)         //  Return the contentView to stop the header from sliding with delete         return [tableView dequeueReusableCellWithIdentifier:@"numberHeaderIdentifier"].contentView;     else         return [tableView dequeueReusableCellWithIdentifier:@"emptyHeaderIdentifier"]; }  - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {     return 75; }  - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {     Number *aNumber = [self.fetchedResultsController objectAtIndexPath:indexPath];     [cell configureSubviewsInCell:cell withNumber:aNumber]; }  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {     [tableView beginUpdates];     [tableView endUpdates]; }  - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {     if (editingStyle == UITableViewCellEditingStyleDelete) {         NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];         [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];     } } 

2 Answers

Answers 1

You should set the hidden property of the labels that you don't want to show when the table view cell is not selected. For example:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {     Number *aNumber = [self.fetchedResultsController objectAtIndexPath:indexPath];      UILabel *label1 = (UILabel *)[cell.contentView viewWithTag:501];     label1.text = [aNumber valueForKey:@"number"];     if (!cell.selected)     {        label1.hidden = YES;     }     else     {        label1.hidden = NO;     }     .....  } 

Then in didSelectRowAtIndexPath:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {     [tableView beginUpdates];     UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];     UILabel *label1 = (UILabel *)[cell.contentView viewWithTag:501];     label1.text = [aNumber valueForKey:@"number"];     label1.hidden = NO;     [tableView endUpdates]; } 

You should look into subclassing UITableViewCell so you don't have to use tags to access subviews.

Answers 2

The 'hiding' solution posted by beowulf is a valid option. In addition and because the swipe (to begin editing) was causing subviews in the cell to become 'unclipped', a method needed to be overrided, like so:

// this method is called as the swipe to delete is started - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(nonnull NSIndexPath *)indexPath {     // only hide for unexpanded (unselected) cells     if ([self.selectedRowIndex compare:indexPath] != NSOrderedSame)     {         NumberTableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];         // a cell subclass method to hide/unhide subviews that fall into         //  the next cell below         [cell subViewsInCellShouldBeHidden:YES];     } } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment