I have a tableView that I\'m inserting rows into at the top.
Whilst I\'m doing this I want the current view to stay completely still, so the rows only appear if you
Based on Andrey Z's answer, here is a live example working perfect for me...
int numberOfRowsBeforeUpdate = [controller.tableView numberOfRowsInSection:0];
CGPoint currentOffset = controller.tableView.contentOffset;
if(numberOfRowsBeforeUpdate>0)
{
[controller.tableView reloadData];
int numberOfRowsAfterUpdate = [controller.tableView numberOfRowsInSection:0];
float rowHeight = [controller getTableViewCellHeight]; //custom method in my controller
float offset = (numberOfRowsAfterUpdate-numberOfRowsBeforeUpdate)*rowHeight;
if(offset>0)
{
currentOffset.y = currentOffset.y+offset;
[controller.tableView setContentOffset:currentOffset];
}
}
else
[controller.tableView reloadData];
-(void) updateTableWithNewRowCount : (int) rowCount
{
//Save the tableview content offset
CGPoint tableViewOffset = [self.tableView contentOffset];
//Turn of animations for the update block
//to get the effect of adding rows on top of TableView
[UIView setAnimationsEnabled:NO];
[self.tableView beginUpdates];
NSMutableArray *rowsInsertIndexPath = [[NSMutableArray alloc] init];
int heightForNewRows = 0;
for (NSInteger i = 0; i < rowCount; i++) {
NSIndexPath *tempIndexPath = [NSIndexPath indexPathForRow:i inSection:SECTION_TO_INSERT];
[rowsInsertIndexPath addObject:tempIndexPath];
heightForNewRows = heightForNewRows + [self heightForCellAtIndexPath:tempIndexPath];
}
[self.tableView insertRowsAtIndexPaths:rowsInsertIndexPath withRowAnimation:UITableViewRowAnimationNone];
tableViewOffset.y += heightForNewRows;
[self.tableView endUpdates];
[UIView setAnimationsEnabled:YES];
[self.tableView setContentOffset:tableViewOffset animated:NO];
}
-(int) heightForCellAtIndexPath: (NSIndexPath *) indexPath
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
int cellHeight = cell.frame.size.height;
return cellHeight;
}
Simply pass in the row count of the new rows to insert at the top.
I faced situation where there are many sections which may have different row count between -reloadData calls because of custom grouping, and row heights vary. So here is solution based on AndreyZ's. It contentHeight property of UIScrollView before and after -reloadData and it seems like more universal.
CGFloat contentHeight = self.tableView.contentSize.height;
CGPoint offset = self.tableView.contentOffset;
[self.tableView reloadData];
offset.y += (self.tableView.contentSize.height - contentHeight);
if (offset.y > [self.tableView contentSize].height)
offset.y = 0;
[self.tableView setContentOffset:offset];
There's really no need to sum up all rows height, the new contentSize after reloading the table is already representing that. So all you have to do is calculate the delta of contentSize height and add it to the current offset.
...
CGSize beforeContentSize = self.tableView.contentSize;
[self.tableView reloadData];
CGSize afterContentSize = self.tableView.contentSize;
CGPoint afterContentOffset = self.tableView.contentOffset;
CGPoint newContentOffset = CGPointMake(afterContentOffset.x, afterContentOffset.y + afterContentSize.height - beforeContentSize.height);
self.tableView.contentOffset = newContentOffset;
...
You don't need to do so much difficult operations, furthermore these manipulations wouldn't work perfectly. The simple solution is to rotate table view, and then rotate cells into it.
tableView.transform = CGAffineTransformMakeRotation(M_PI);
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.transform = CGAffineTransformMakeRotation(M_PI);
}
Use [tableView setScrollIndicatorInsets:UIEdgeInsetsMake(0, 0, 0, 310)]
to set relative position to scroll indicator. It will be on the right side after you table view rotation.
Simple solution to disable animations
func addNewRows(indexPaths: [NSIndexPath]) {
let addBlock = { () -> Void in
self.tableView.beginUpdates()
self.tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .None)
self.tableView.endUpdates()
}
tableView.contentOffset.y >= tableView.height() ? UIView.performWithoutAnimation(addBlock) : addBlock()
}