I need to reload tableview, but in somehow I want to keep the scroll position. Any way to do it? Maybe store content offset and in viewDidLayoutSubviews I should reset it?
TableView does not reset scroll position. It maintains content offset even after reloadData function is called. So no need to do anything, if you want to keep pixel position.
If you are changing row height at the time of reloading data or changing datasource then you can use scrollToRowAtIndexPath:atScrollPosition:animated: method.
You can save your current offset before reloading the table use this method to save your current offset
self.tableView.contentOffset.y
Or you can Reload like this it will Reload your table from your current Offset
Try this:
[UIView animateWithDuration:0.1 delay:0 options:0 animations:^{
self.tableView.contentOffset = CGPointMake(0, currentOffset);
} completion:^(BOOL finished) {
[self.tableView reloadData];
}];
After reloading the table view you need to call the TableView's method scrollToRowAtIndexPath:atScrollPosition:animated:
Just provide the index path, scroll position which could be one of the following
UITableViewScrollPositionNone,
UITableViewScrollPositionTop,
UITableViewScrollPositionMiddle,
UITableViewScrollPositionBottom
and YES/ NO in animated parameter.
just call scrollToRowAtIndexPath:atScrollPosition:animated: before you use reloadData (with animation:NO)
Also, be carefull in case you have less cells in the updated tableview to prevent crashes.
Hope it helps
Related
I try to implement a tableView where rows additional rows are inserted with an animation while the rows are visible. I update the array for the datasource and call:
[self.tableView insertRowsAtIndexPaths:addedIndexPaths withRowAnimation:(UITableViewRowAnimationMiddle)];
I want the tableview to not scroll at all and the rows to be inserted on screen (no over the visible are).
In some section especially the last section of the tableview the cells are inserted the tableview scrolls to completely different section.
I tried different row animation, calling layoutIfNeeded inside of and beginUpdate / endUpdate block, set the correct content offset inside of the beginUpdate / endUpdate block or reload the entire section.
Nothing works. The scrollview always scrolls up.
The cells size them selves using autolayout-constraints. On the top half of the tableview the cells are inserted as I expected.
How can I fix the content Offset while cells are inserted with an animation?
How can I debug that animation?
I faced same issue and after trying a lot found solution that if I remove section header height as UITableViewAutomaticDimension then adding and removing rows from UITableView works perfectly and table view also fixed at same position.
tableView.sectionHeaderHeight = 10;
tableView.estimatedSectionHeaderHeight = UITableViewAutomaticDimension;
remove above 2 lines if added.
tableView.estimatedRowHeight = 15;
tableView.rowHeight = UITableViewAutomaticDimension;*
Row with Automatic Dimension will not create any issues.
But section header view with Automatic Dimension will create issue.
Thanks.
This is a know bug with the UITableViews, it's been there quite a long time and hasn't been fix (by the looks of it, it never will).
The root of this is because your cells are of dynamic sizes and (I'm assuming) you are using the default 'UITableViewAutomaticDimension'. To fix this you need to drop the use of 'UITableViewAutomaticDimension' and calculate the size of each cell. This should help with the bounciness of the table view but probably wont be perfect.
Another way is to rely on CATransaction to lock and keep the table view position after the insert.
It should look something like this (probably, I didn't test it):
CGFloat offset = self.tableView.contentSize.height - self.tableView.contentOffset.y;
[CATransaction begin];
[CATransaction setDisableActions:YES];
[CATransaction setCompletionBlock: ^{
// Code to be executed upon completion
}];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths: indexPaths
withRowAnimation: UITableViewRowAnimationAutomatic];
self.tableView.contentOffset = CGPointMake(0,
self.tableView.contentSize.height - bottomOffset);
[self.tableView endUpdates];
[CATransaction commit];
I have a UITableViewController and when the user scrolls to the top, I want to add a bunch of cells above the first cell without affecting the current scroll position (just like iMessage)
I know I can use insertRowsAtIndexPaths to do this without reloading the data, but I just want to do it the simplest way possible first. So I am overwriting the data and calling reload, then calling setContentOffset, but no matter what I set the offset to, the table always reverts to the top.
// in an NSNotification handler
//...
dispatch_async(dispatch_get_main_queue(), ^{
// get old content height
CGSize oldContentSize = self.tableView.contentSize;
NSLog(#"old content height: %f", oldContentSize.height);
// update tableView data
self.messages = updatedMessages;
[self.tableView reloadData];
// get new content height
CGSize newContentSize = self.tableView.contentSize;
NSLog(#"new content height: %f", newContentSize.height);
// move to user scroll position
CGPoint newContentOffset = CGPointMake(0, newContentSize.height - oldContentSize.height);
[self.tableView setContentOffset:newContentOffset];
});
When I run this I get:
old content height: 557.765625
new content height: 1249.050781
but the tableView reverts to the top instead of maintaining its scroll position.
I found that if I call [self.tableView setContentOffset:newContentOffset animated:YES]; It always scrolls down to the correct position, but the movement is unacceptable.
How can I maintain the scroll position after reloading the tableView data?
I've looked at these:
setContentOffset only works if animated is set to YES
UIScrollView setContentOffset: animated: not working
UITableView contentOffSet is not working properly
but their solutions don't work in my case.
Try this
[self.tableView setContentOffset:newContentOffset animated:NO]
In my tableview I need to animate the UI of every cell as the tableview reloads its data.
This needs to a custom animation, not just a fade or default transition.
For example, When tapping the 'Edit' button, in my view, the tableview reloads and each cell updates its UI for this new edit mode.
However, during this reload I have tried using a UIView animation block to update a constraint on a UILabel in my cells, but it will not animate.
Here is the code I run when I call reloadData on my tableview. This is called in cellForRowAtIndexPath method.
[UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^
{
//does not animate
_lblContainerLeftConstraint.constant = 18;
[self setNeedsLayout];
//does animate
_reorderIcon.alpha = 0.5f;
} completion:nil];
I think you need to do this in willDisplayCell rather than cellForRowAtIndexPath since that is called just before display which is as close as you can get to the point it actually appears on screen.
Then set the new constraint value before the animation block and also call [cell.contentView setNeedsLayout] to indicate that layout is needed on the cell content.
Finally only add [cell.contentView layoutIfNeeded] and your alpha change in the animation block which should animate the constraint change over your time period.
For some reason, my UICollectionView animates the transition inside the visible cell when calling reloadData.
From what I understood it shouldn't do that, and that's what I am trying to do.
Why would the collection view animate on reload data? And how could I stop it?
I will be eventually using [UIView setAnimationsEnabled:YES/NO], but I would be hoping to fix it without too much extra code.
[UIView performWithoutAnimation:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
}];
Following on from a previous SO question which I asked, I am attempting to animate the change in height of a UICollectionView (which is yellowBox in the example). This change in height is being triggered by modifying the auto layout constraints on the collection view with the following code:
- (IBAction)expandYellowBox:(id)sender {
[UIView animateWithDuration:0.5
animations:^{
self.yellowBoxHeightConstraint.constant += 50;
[self.view layoutIfNeeded];
}];
}
However, when I call [self.view layoutIfNeeded] this results in the collection view being reloaded, so it flashes visibly to the user. However, I don't want the collection view to reload but instead just to animate its height change. Is there any way to either avoid -layoutIfNeeded reloading the collection view, or an alternative way to animate the constraint height change which doesn't call a method which has the side-effect of reloading the collection view?
In case anyone else encounters this problem, it was because I was actually calling [self.collectionView reloadData] a few lines above the animation block (and didn't notice!). It seems that calling -reloadData and -layoutIfNeeded causes the collection view to flash. Removing the call to -reloadData resolves the problem.