UITableViewCell selection flickers on reload - ios

I have a UITableView which I have hooked up to a NSFetchedResultsController. When an object is updated, I use reloadRowsAtIndexPaths to reload the cell. I want to keep the cell selected while it is reloaded. The below code is how I am reselecting the cell after the update. It works, but the cell displays unselected for about half a second before becoming selected again and looks bad. self.selectedIndexPath is set in didSelectRowAtIndexPath.
I've also tried setting the cell to selected and highlighted in cellForRowAtIndexPath, but that did nothing.
Does anyone know how to prevent the flickering? I'm using iOS 8.3 BTW.
// Called in controllerWillChangeContent
[self.tableView beginUpdates];
...
// Called in didChangeObject
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
...
// Called in controllerDidChangeContent
[self.tableView endUpdates];
if( self.selectedIndexPath ) {
[self.tableView selectRowAtIndexPath:self.selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}

Related

Reload UITableView without reloading header section

I have a UITableview with section and index title. When user click on a cell a option view of height 42 gets display in that cell. To display that option I reload the cell. But section header is also getting updated. That gives bizarre animation. How to reload only cell,without getting called for other delegate method like heightForHeaderInSection and viewForHeaderInSection.
I think you should only update the particular row for indexPath, try the code below
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
}
It might help you.
Cheers.
In Swift 2.0 & above
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
tableView.endUpdates()
}
There are several methods for reloading the tableview.
To reload whole section including section's cell.
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
Example:
[tableVIewContent reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic];
To reload single/multiple cells
- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath > )indexPaths withRowAnimation:(UITableViewRowAnimation)animation
Example:
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:1]] withRowAnimation:UITableViewRowAnimationFade];
To reload whole tableview.
- (void)reloadData;
// reloads everything from scratch. redisplays visible rows. because we only keep info about visible rows, this is cheap. will adjust offset if table shrinks

tableView beginUpdates / endUpdates block reloading entire table even when empty

I have a tableView that periodically gets updated by data coming from a remote service. I load the data, and store the indexPaths of various data that I just inserted, deleted or updated. I then have a begin/endUpdates block that completes the necessary operations, as seen below.
[self.tableView beginUpdates];
if (pathsToDelete) {
[self.tableView deleteRowsAtIndexPaths:pathsToDelete withRowAnimation:UITableViewRowAnimationNone];
}
if (pathsToRefresh) {
[self.tableView reloadRowsAtIndexPaths:pathsToRefresh withRowAnimation:UITableViewRowAnimationNone];
}
[self.tableView insertRowsAtIndexPaths:indexPathsToAdd withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
I noticed recently that cells were being reloaded way more than I was expecting. Following through in the debugger, I noted that in cases where a single record was being refreshed (ie pathsToRefresh was the only one that had anything, and it had only a single index) the entire table was actually reloading. By that, I mean I was seeing requests to the dataSource for each and every cell in the table.
In debugging, I started stripping things down. I got all the way to the point where I only had
[self.tableView beginUpdates];
[self.tableView endUpdates];
And even then, I was seeing the entire table reload (ie cellForRowAtIndexPath was fired for every value in the datasource). So I assumed something else was happening that I'd missed..but removing those two methods resulted in the reload stopping.
Shouldn't begin/endUpdates do nothing in cases where nothing is within the block? I'm at a loss on what is actually happening here, as the doc indicates all they do is bookend table operations - and in this case I have none.
objective c iOS reloadRowsAtIndexPaths , reloadSections
if([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1 == -1){
row = 0;
}else{
row = [self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1 ;
}
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: (row) inSection: ([self.tableView numberOfSections]-1)];
// [self.tableView reloadData];
[self.tableView beginUpdates];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
NSLog(#”Number of Sections %ld”, (long)[self.tableView numberOfSections]);
NSLog(#”Number of Rows %ld”, [self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1);

Update Specific cells in a tableView without calling reloadData

I have an app in which I have a UITableview with custom cells and headers. The cells have an inputView so when selected they become first responder and allow the user to input data.
I want to be able to update the visible TableViewCell and header information on the fly while the user is changing it.. easy, just call [tableview reloadData]; ..
Unfortunately this causes the inputview to resign first responder and hide itself.
Is there any way that I can get a reference to the cell itself inside the UITableview so that I can just change the text property? (cellForRow:atIndexPath: returns a new object with the same properties so doesn't work) It seems like the only easy solution may be to store a reference the cells in a dictionary each time a cell is populated, not really the ideal solution.
cellForRowAtIndexPath is literally just
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *orderCell;
static NSString *productCellIdentifier = #"ImageDetailCellIdentifier";
orderCell = [self.tableView dequeueReusableCellWithIdentifier:productCellIdentifier forIndexPath:indexPath];
//set a bunch of properties orderCell.blah
return orderCell;
}
According to UITableView documentation, -cellForRowAtIndexPath: returns an object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.
That is also how I remember it. I don't think your observation is correct that it returns a new object. If the cell is visible you will get hold of it.
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade]; ///as your choice in animation
[tableView endUpdates];
or else
[tableView beginUpdates];
// do some work what ever u need
[tableView endUpdates];
For reloading specific rows, you can use
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
For example,
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:2 inSection:1];
NSArray* indexArray = [NSArray arrayWithObject:indexPath];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];

ios reload tableview in beginUpdates

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...

Tableview - wait for cell to be removed before adding a new one

I have a table view, in which if you select a row, it add a picker below the row. But if another row is selected, it hides the first picker (removed the row with the picker) and then adds a new picker.
Now my question is, how to I wait for the remove animation to finish before adding a new row?
This is how I add a new row. It's in the didSelectRow method.
NSIndexPath *selectedIndex = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
pickerInsertedAtIndexPath = selectedIndex;
NSArray *indexes = #[selectedIndex];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationMiddle];
[tableView endUpdates];
This is how I remove a row. This is in the willSelectRow method.
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationMiddle];
[tableView endUpdates];
Unfortunately there are no callbacks as to when the table view animations end. You'll have to wait for an interval of your choice before adding the new picker.
Not sure if this matches your scenario but can you use:
tableView:didEndDisplayingCell:forRowAtIndexPath:
A UITableViewDelegate callback that will inform you when a cell has been removed from the UITableView?

Resources