How to get rid of unwanted whitespace when collapsing TableViewCell - ios

I have a UITableView with cells that expand/collapse when users tap on them, using:
-(void)tableView:(UITableView *)_tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
...
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
...
}
After the reloadRowsAtIndexPath is run, I have heightForRowAtIndexPath return a different height depending on whether the cell is collapsing or expanding:
-(CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// if expand
return 200;
// if collapse
return 49;
}
When I collapse a cell at the bottom of the table, the table shrinks, but it is brought down way too far, leaving a significant amount of whitespace at the top of the table. I've tried [tableView scrollToRowAtIndexPath:indexPath] after calling reloadRowsAtIndexPaths, which solves the problem, but that makes the table jumpy. It would go down too far leaving whitespace then jump back to the top. How can I shrink the table cell without making it scroll down too far?

After you change something that affects tableView height, you can use these code to update cell height without reloading the table:
[tableView beginUpdates];
[tableView endUpdates];

Maybe you can use a UIView animation in main thread to avoid this,such as:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.3 animations:^{
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}];
});
Then try:
if (#available(iOS 11.0, *)) {
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic;
}

Related

Inserting UIView into TablewView with InsertRowsAtIndexPaths using ContentView

I lost a bit nerves on this case. I have UIView with few images as buttons. I would like to insert it with insertRowsAtIndexPaths:
I have no idea how to start with that, and I really searched every site on google. I even found something that works like a charm ( http://jackkwok.github.io/JKExpandTableView/ ) but I still cannot make it right.
Here is my didSelectRowAtIndexPath method:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
int selectedRow = indexPath.row;
NSLog(#"touch on row %d", selectedRow);
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
PrototypeCell *prototypeCell =(PrototypeCell *)[tableView cellForRowAtIndexPath:indexPath];
if (prototypeCell.stretched == NO){
[UIView animateWithDuration:1 animations:^{
prototypeCell.View.frame = CGRectMake(0, 0, 320, 120);}
completion: nil];
prototypeCell.stretched = YES;}
else {
[UIView animateWithDuration:1 animations:^{
prototypeCell.View.frame = CGRectMake(0, 0, 15, 120);}
completion: nil];
prototypeCell.stretched = NO;
}
// Start a new core animation transaction
[CATransaction begin];
// Set a completion block for the animation
[CATransaction setCompletionBlock:^{
//
// Update the data model to add a new section
// [_data addObject:[DetailView init] alloc];
NSInteger item = self.thingList.count-1;
// Animate the new section apperance
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForItem:item inSection:0], nil] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"Array is: %#", _data);
// [tableView endUpdates];
}];
[CATransaction commit];
}
My head is already numb from that problem. I cannot even understand basic inserting, how I write what I would like to insert here?
Any Help appreciated!
Based on your described intent, I'm not entirely sure you need or want to insert table rows. It looks like what you are trying to achieve is to simply expand the height of a given row to reveal some extra buttons when that row is selected.
Changing the height of row is covered How to dynamically resize UITableViewCell height
Essentially you can have your PrototypeCell have some extra content (the buttons) that is usually clipped. When the view is selected, you simply change the height to make sure all of the buttons would be visible and you indicate to the tableview to reload the row that was selected.
Should you need to insert rows, this was covered in how to properly use insertRowsAtIndexPaths?
Good luck!

UITableview scrolling postion on didselectrow

I have a UITableView which consist of Chapters and Subchapters. On selecting Chapters the respective Subchapter will expand in UITableView. When I click the last Chapter the subchapter is not visible in the screen. Have to scroll below automatically when the subchapters appear.
You can either use
[self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
Or use
CGPoint bottomOffset = CGPointMake(0, yourTableView.contentSize.height - yourTableView.frame.size.height);
[table setContentOffset:bottomOffset]
This will scroll the tableView to the bottom when a new cell will be inserted to your tableView
On didSelectRowAtIndexPath method you need something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
[tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationNone];
CGRect sectionRect = [tableView rectForSection:indexPath.section];
[tableView scrollRectToVisible:sectionRect animated:YES];
...
}
Hope it helps.

UITableViewCell expand animation?

I would like to make something like expandable cells. Result I'm trying to achieve is:
Actually I have:
Here is my code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
DoctorCell *cell = self.prototypeCell;
DoctorModel *doctor = [self.fetchController objectAtIndexPath:frcIndexPath];
// depending on isActive property I add (or do not add) some content.
[cell cellForDoctor:doctor isActiveCell:[self.activeCellIndexPath isEqual:indexPath]];
[cell setNeedsUpdateConstraints];
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height + 1;
}
Here is my cell selection method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSIndexPath *oldIndexPath = self.activeCellIndexPath;
if ([indexPath isEqual:self.activeCellIndexPath]) {
self.activeCellIndexPath = nil;
oldIndexPath = nil;
} else {
self.activeCellIndexPath = indexPath;
}
[self.doctorTableView beginUpdates];
[self.doctorTableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, oldIndexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
[self.doctorTableView endUpdates];
[self.doctorTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
As you can see, my animation looks weird (kind of moving to wrong position, jumps, etc). What I'm doing wrong? Or do I need to pick another approach for expanding cells?
You can use UITableViews animation automation like this:
Call [tableView beginUpdates];
Change the data source.
Insert or delete rows and sections, or reload them
This should cause new heights to be calculated, etc.
Make sure you use something appropriate for the withRowAnimation parameter of these methods
Call [tableView endUpdates];
Your animation should now perform as expected.
Maybe your problem is that you selected UITableViewRowAnimationNone for the row animation.

UITableView - scrolls sometimes when expanding a cell on 7.1, not on 7.0

This behavior is iOS 7.1 only, on 7.0, it works as intended.
I've got a UITableView with cells of different height. When tapping on one of them, it expands via
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row != self.selectedCellIndexPath.row) {
// Close previously opened cell
if (self.selectedCellIndexPath != nil) {
[tableView beginUpdates];
[(MyTableViewCell *) [tableView cellForRowAtIndexPath:self.selectedCellIndexPath] collapse];
[tableView endUpdates];
}
self.selectedCellIndexPath = indexPath;
[tableView beginUpdates];
[(MyTableViewCell *) [tableView cellForRowAtIndexPath:indexPath] expand];
[tableView endUpdates];
}
else if (indexPath.row == self.selectedCellIndexPath.row) {
self.selectedCellIndexPath = nil;
[tableView beginUpdates];
[(MyTableViewCell *) [tableView cellForRowAtIndexPath:indexPath] collapse];
[tableView endUpdates];
}
}
When tapping on a row at the top of the tableView, everything behaves as intended - the cell is expanded downwards, the top of the cell stays where it is. But when scrolling down and tapping on a cell more at the bottom of the tableview, the cell moves downwards and expands. The further down the cell is, the worse it is.
I'm calculating the table cells heights this way:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
self.prototypeCell = [[MyTableCell alloc] initReuseIdentifier:CellIdentifier];
[self configureCell:self.prototypeCell forIndexPath:indexPath];
float height = 38;
if ([indexPath isEqual:self.selectedCellIndexPath]) {
height += [self.prototypeCell expandedHeight] + 5;
}
return height;
}
I'm irritated that the effect is different if I tap on a cell at the top or at the bottom of the tableView. Furthermore, this effect is only the first time after scrolling down. When repeating, the cell stays at its position, as intended. Only after scrolling up and down again, it behaves wrong the first time.
I solved the problem; it was due to estimatedHeightForRowAtIndexPath, I removed the method and now the expanding/collapsing works as expected.

The sectionView has been loaded on the cell

As the picture shows. I make a tableview which can splite by inserting one row (the gray one) when I click on the cell, click again to cancel the splite:
The code is as below:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int clickCellRow = [indexPath row] + 1;
int clickCellSection = [indexPath section];
[self beginUpdates];
if (isEditFlag == NO) {
isEditFlag = YES;
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:clickCellRow inSection:clickCellSection]] withRowAnimation:UITableViewRowAnimationFade];
}
else {
isEditFlag = NO;
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:clickCellRow inSection:clickCellSection]] withRowAnimation:UITableViewRowAnimationFade];
}
[self endUpdates];
}
It works well on IOS6, but on IOS7 one bug happened. When one cell is clicked and the splited row is inserted, then the sectionView is forced to go outside of the screen:
After cancelling the splite, and scroll the hidden cell up. The table turn to be as below :
It seems that the sectionView has been loaded on the cell! How does this happened and how to fix it?

Resources