I have UITableview which has dynamic row height using AutoLayout.
In iOS 8.4, if set scrollToRowAtIndexPath or setContentOffset its not scroll to last indexpath. in iOS 9.x it is working. Kindly help
[tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:arr.count - 1 inSection:RootArr.count - 1] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
dispatch_after(0, dispatch_get_main_queue(), ^{
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
});
It is OK
Related
I am trying to create a chat bot like application, I have used a UITableView with custom cells to fit my needs. Whenever a new message is added, I create and insert a new row and then scroll to the bottom of the UITableView. Everything works fine till a certain point, but when the height of the cells change (I have two different type of cells), the animation is messy, it doesn't smoothly scroll to the end and the entire UITableView flashes, which is not a good user experience. I have tried a couple of approaches:
1 - Add the data to the data source array and reload the UITableView, then scroll to the bottom.
2 - Use insertRowsAtIndexPaths then scroll to the bottom.
Both of them have the same issue with scrolling. I have used scrollToRowAtIndexPath to get to the bottom of the UITableView
I have uploaded the code of a demo app that represents simulate the same issue here so it will be easy to understand. Here is a video of the issue. Any help is really appreciated.
This issue MAY NOT occur on a simulator, kindly run the demo project on a device.
After reading all the comments and having a discussion in chat, I noticed this is happening on the iPhone 5C (10.3.3). I ran the demo on an iPhone 5S (11.3) and the issue does not occur. Not sure if this has to do something with the OS.
Reloading whole tableview results in messy scrolling instead insert row at last position.
Make following changes in your Action Methods
- (IBAction)btnLargeCellClicked:(id)sender { // To add large green colored row.
/************ This is the FIRST approach. ***********/
[arrHeight addObject:#"100"];
[arrData addObject:#"1"];
NSIndexPath* ip = [NSIndexPath indexPathForRow:[_myTable numberOfRowsInSection:0] inSection:0];
[_myTable insertRowsAtIndexPaths:#[ip] withRowAnimation:UITableViewRowAnimationFade];
[self scrollTableviewToLastRow];
/************ This is the SECOND approach. ***********/
// [arrHeight addObject:#"100"];
// [_myTable beginUpdates];
// NSIndexPath *row1 = [NSIndexPath indexPathForRow:arrData.count inSection:0];
// [arrData insertObject:#"1" atIndex:arrData.count];
// [_myTable insertRowsAtIndexPaths:[NSArray arrayWithObjects:row1, nil] withRowAnimation:UITableViewRowAnimationFade];
// [_myTable endUpdates];
// [self scrollTableviewToLastRow];
}
And
- (IBAction)btnClicked:(id)sender { // To add small red colored row.
/************ This is the FIRST approach. ***********/
[arrHeight addObject:#"50"];
[arrData addObject:#"1"];
NSIndexPath* ip = [NSIndexPath indexPathForRow:[_myTable numberOfRowsInSection:0] inSection:0];
[_myTable insertRowsAtIndexPaths:#[ip] withRowAnimation:UITableViewRowAnimationFade];
[self scrollTableviewToLastRow];
/************ This is the SECOND approach. ***********/
// [arrHeight addObject:#"50"];
// [_myTable beginUpdates];
// NSIndexPath *row1 = [NSIndexPath indexPathForRow:arrData.count inSection:0];
// [arrData insertObject:#"1" atIndex:arrData.count];
// [_myTable insertRowsAtIndexPaths:[NSArray arrayWithObjects:row1, nil] withRowAnimation:UITableViewRowAnimationFade];
// [_myTable endUpdates];
// [self scrollTableviewToLastRow];
}
Hope this helps :)
After seeing your source, can say tableView reloadData reloads cells every time, that makes animation more busy every additional cell.
For your goals you should use another system:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[indexPathOfYourCell] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
And than, maybe you will need scrollToRowAtIndexPath at the end too
You would need this, change second approach like below
[arrHeight addObject:#"50"];
// [_myTable beginUpdates];
NSIndexPath *row1 = [NSIndexPath indexPathForRow:arrData.count inSection:0];
[arrData insertObject:#"1" atIndex:arrData.count];
[_myTable insertRowsAtIndexPaths:[NSArray arrayWithObjects:row1, nil] withRowAnimation:UITableViewRowAnimationNone];
[_myTable reloadRowsAtIndexPaths:#[row1] withRowAnimation:UITableViewRowAnimationNone];
// [_myTable endUpdates];
[self scrollTableviewToLastRow];
I have set the row insertion with the following code. I am only using UITableViewRowAnimationNone when inserting and deleting the rows, but sometimes ,as you can see in the gif below, the row animates in from the top or bottom. For the most part it doesn't animate, as I want it, but sometimes it animates on insertion and deletion. I am not talking about the table view expanding to show the inserted cell, I mean the cell appears to be sliding in from the bottom or top.
Here is the method that controls the insertion animation:
- (void)contentHeaderFooterView:(NFContentHeaderFooterView *)headerFooterView sectionOpened:(NSInteger)section{
NSIndexPath *pathToAdd = [NSIndexPath indexPathForRow:0 inSection:section];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[pathToAdd] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
And here is the method that controls the deletion animation.
- (void)contentHeaderFooterView:(NFContentHeaderFooterView *)headerFooterView sectionClosed:(NSInteger)section{
NSIndexPath *pathToDelete = [NSIndexPath indexPathForRow:0 inSection:section];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[pathToDelete] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
I've had similar issues with table updates not performing the animation I gave it directly. I can't say for sure why, but one thing I can suggest is, instead of doing a specific row deletion between begin/endUpdates, you can just to a hard reloadData.
Answered here: https://stackoverflow.com/a/37352789/577237
Reposted since it's brief:
[UIView performWithoutAnimation:^{
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:rowsToRemove withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}];
Note that this is iOS 7.0+
When I Use
[self.chatContentTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:bottomFlag+2 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
when the animated set YES,my tableView will scroll,but when the animated set NO,it donest work
I also found it.
My code is:
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]atScrollPosition:UITableViewScrollPositionMiddle animated:animation];
It work after remove reloadData.
I guess the reason why it does not take effect is that it's executed immediately after reload
I change the height of a cell (when image downloaded) with method like that
-(void)didHeightChanged:(float)imageHeight atIndex:(NSInteger)indexPath
{
[dictionary setObject:imageHeight forKey:indexPath];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
Everything works well with first data, but when I reload UITableView with second data , probably beginUpdates method doesnt ended and I got issues - when I delete and reload UITableView, cell dont disappear, UITableView shows wrong cells
How can I stop beginUpdates immediately before reload new data?
You should either call [self.tableView reloadData] or [self.tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathWithRow:index inSection:0]]]; // or indexPath if instead of passing a NSInteger you pass a NSIndexPath * to the method.
I found the answer
[self.tableView beginUpdates];
[self.tableView endUpdates];
it was called in background thread...
I've used reloadRowsAtIndexPaths: on iOS 6, and it ran fine.
[self.tableview beginUpdates];
[self.tableview reloadRowsAtIndexPaths:indexPath withRowAnimation:UITableViewRowAnimationNone];
[self.tableview endUpdates];
This calls cellForRowAtIndexPath: of the tableview on iOS 6, but, it doesn't call cellForRowAtIndexPath: of the tableview on iOS 7, so I can't update the specified cell.