When reloading a UITableView section, all sections flash - ios

I'm using a UITableViewController, and am using:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:sectionNumber] withRowAnimation:UITableViewRowAnimationNone];
to reload an individual section of the tableview (to animate the insertion of new cells). The issue is that all of the sections, and their cells, flash white briefly every time this call is made. This does not occur if I use
[self.tableview reloadData];
but does occur no matter which row animation I use.
I'm aware that I can use insertRowsAtIndexPaths:withRowAnimation:, but I currently have a race condition that doesn't allow me to use that. I will, at some point, fix that, but in the meantime I would like to know why all sections cells flash while I'm reloading a single section. In addition, if I can turn off the flash and just animate the insertion / deletion of cells, that would be ideal.

I believe that it flashes because when you reload a specific section, it still has to recalculate the size of all the visible sections. Hence the flash. Without using insertion/deletion (because it knows the table will only change by one), you can't get past that.
If you are just trying this in the simulator though, it is possible that the flash will either disappear or be less noticeable when loaded on an actual device.

May be it's too late. But it could help someone.
Obj-c:
[UIView performWithoutAnimation:^{
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:[indexPath section]] withRowAnimation:UITableViewRowAnimationNone];
}];
Swift 5:
UIView.performWithoutAnimation {
self.tableView.reloadSections(NSIndexSet(index: indexPath.section), with: .none)
}

Related

iOS UITableView behaviour broken when not active

My current set up is the following:
Root Tab Bar:
Collection view with magazines
Bookmarks (with a table view)
Others
You can add a bookmark from a magazine in the collection view and also remove it from there.
The behaviour I'm seeing is the following:
I start the application, the table view queries the number of sections, number of cells, but not the cellForRowAtIndexPath. I could understand why, as there is no cell in the active view, so no data should be loaded.
When I add a bookmark from the collection view, it adds it to the array (via a notification) and requests the tableview to be reloaded. As there isn't an initial entry, it goes through the motions described above. When I press it again to remove the bookmark the entry is removed from the array. This is where it gets interesting because the first thing the table calls is not the number of sections or rows but the cellForRowAtIndexPath. As the array is empty, the application crashes on a request for data on index 0.
My question is why does the cell creation get called in that order? Is there any way to avoid it?
If you changed the section, try calling - (void)reloadSections:(NSIndexSet *)sections before you call reloadData
https://developer.apple.com/library/ios/DOCUMENTATION/UIKit/Reference/UICollectionView_class/index.html#//apple_ref/occ/instm/UICollectionView/reloadSections:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationLeft];
The reason this was happening is because I was attempting to change something about the table before I reloaded the data.
[self.tableView setSeparatorStyle: !_helpText.hidden ? UITableViewCellSeparatorStyleNone : UITableViewCellSeparatorStyleSingleLine];
[self.tableView reloadData];
That was for removing the lines so a message can be displayed. However that update was using old data as reloadData had not been called.
[self.tableView reloadData];
[self.tableView setSeparatorStyle: !_helpText.hidden ? UITableViewCellSeparatorStyleNone : UITableViewCellSeparatorStyleSingleLine];
Reversing them fixed the issue.

How to delete rows from UITableView without animation in IOS

I have an accordion type of UITableView that works but I just need to adjust the animation slightly. When a row is clicked a method is called that deletes the rows that are showing then adds the new rows to show. I don't want to animate the rows being deleted. I only want to animate the part when the rows are being added. I can use [UIView setAnimationsEnabled:NO]; to turn off the animation all together but I just want to turn it off for the deleting part.
[self.unitListTableView beginUpdates];
[self.unitListTableView deleteRowsAtIndexPaths:delete withRowAnimation:UITableViewRowAnimationTop];
[self.unitListTableView insertRowsAtIndexPaths:added withRowAnimation:UITableViewRowAnimationFade];
[self.unitListTableView endUpdates];
Any help appreciated.
Call reloadData on your table view and it updates without any animation.

Middle animation in grouped table view looks horrible

I've found similar question, but there is no answer (sorry, answer just doesn't work).
So I have grouped table and I want to animate content update instead of doing [tableView reloadData].
I do that by using this piece of code:
// Data source already updated here, but reloadData wasn't called
[self.tableView beginUpdates];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationMiddle];
[self.tableView endUpdates];
I uploaded 2 examples of the animation:
Plain: http://cl.ly/3u1M3l1w3V3J (slow motion)
Grouped: http://cl.ly/1O3Z2M280n0z (slow motion)
As you can see difference is huge.
I don't change my code at all, just change tableView style in the storyboard.
Does it men that there is no other way then subclassing UITableView and UITableViewCell and implement my very own animation using CoreAnimation?
Implementing your own animation with CoreAnimation shouldn't be necessary when it comes to animating the rows of the table.
UITableView supports much more advanced animations than simply reloading a section and I suggest that you take a look at them.
Since you are shuffling the rows in your videos you should take a look at moveRowAtIndexPath:toIndexPath: (on UITableView). You put the calls to it within beginUpdates and endUpdates.
By knowing the order before and after the re-shuffle you can move all the rows into their new places and have them slide into their correct place.
It will take some thinking to figure out where each row should go but it will be much easier than rolling your completely custom solution.

deleteRowsAtIndexPaths without animation

I got an app with a UITTableView. This table is updatable. And when in the next update the number of rows are less than in previous version, i implement the UITableView's method - deleteRowsAtIndexPaths.
I do it in this way:
[table beginUpdates];
[table deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
[table reloadRowsAtIndexPaths:indexPathsReload withRowAnimation:UITableViewRowAnimationNone];
[table endUpdates];
But when i implement this code there are animations. And this animation is really bad. A lot of black leaks. But i did write - withRowAnimation:UITableViewRowAnimationNone in both methods: delete and reload.
Why? How can i reload and delete rows without animation?
Usually the way this is done is by modifying the data source of the table, and calling reloadData on the table.
maybe you try to work with NSMutableArray (delete row by removeObjectAtIndex:indexPath.row) in TableView and reload the whole tableview by using [tableView reloadData] ?
You can try to make that "gesture" out of the table,and try reload table
Unlike what the name suggests *UITableViewRowAnimationNone* doesn't help at all.
Maybe setting the alpha on the cell works as suggested here. Not sure though.
problems with animation when deleting the last row of a TableView in ios7

Animate the insertion of a new section in UITableVIew

I have this button on my view, and when I press it I insert a new section in my table view ( I have a logical condition in my
-(NSInteger) numberOfSectionsInTableView:(UITableView*)tableView
{
if (slide==TRUE) return 2;
return 1;
}
And also in my -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath. My section is added as it should, but I have read somewhere that this can be animated, because when I press my button the section is added but with no animation. I think I should use this -(void)insertSections:(NSIndexSet*)sections withRowanimation(UITableViewRowAnimation) animation but I haven't found a proper example on the web.
Manipulating rows and sections into UITableView using animation is made pretty easy using the following API's (emphasis on the last two):
insertRowsAtIndexPaths:withRowAnimation:
insertSections:withRowAnimation:
deleteRowsAtIndexPaths:withRowAnimation:
deleteSections:withRowAnimation:
beginUpdates
endUpdates
Updating the Data Model
You should update your data model anywhere between the beginUpdates and endUpdates methods. It doesn't matter if you update your data model before or after insertion or deletion methods just so long as you do it between the beginUpdates and endUpdates methods.
Do not Insert Rows for New Sections You are Inserting
When adding a new section using the insertSections:withRowAnimation: method, you do not need to call insertRowsAtIndexPaths:withRowAnimation: to add rows into it. The insertRowsAtIndexPaths:withRowAnimation: method is just for animating an existing section changing. Similarly, you do not need to call deleteRowsAtIndexPaths:withRowAnimation: when you remove a section using deleteSections:withRowAnimation:.
Regarding Deleting and Inserting:
I generally do these in separate beginUpdates: endUpdates calls, however you can insert and delete at the same time. Just be aware that the UITableView will first try to delete rows / sections and then try to insert them regardless of the order you do it in your code.
Discussion part of deleteRowsAtIndexPaths:withRowAnimation:
Note the behavior of this method when it is called in an animation
block defined by the beginUpdates and endUpdates methods. UITableView
defers any insertions of rows or sections until after it has handled
the deletions of rows or sections. This happens regardless of ordering
of the insertion and deletion method calls. This is unlike inserting
or removing an item in a mutable array, where the operation can affect
the array index used for the successive insertion or removal
operation. For more on this subject, see “Batch Insertion and Deletion
of Rows and Sections” in Table View Programming Guide for iOS.
Example of inserting into a section:
int indexOfNewSection = 4; // TODO: change to meaningful value
[self.tableview beginUpdates];
[self.tableview insertSections:[NSIndexSet indexSetWithIndex:indexOfNewSection]
withRowAnimation:UITableViewRowAnimationAutomatic];
// Update data model
[self.sections insertObject:sectionObj atIndex:indexOfNewSection];
[self.tableview endUpdates];
UITableViewRowAnimation is an enum declared at the top of UITableView.h You can also view it in the UITableView reference. It's smallish, so I'll just paste it!
typedef enum {
UITableViewRowAnimationFade,
UITableViewRowAnimationRight, // slide in from right (or out to right)
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone, // available in iOS 3.0
UITableViewRowAnimationMiddle, // available in iOS 3.2. attempts to keep cell centered in the space it will/did occupy
UITableViewRowAnimationAutomatic = 100 // available in iOS 5.0. chooses an appropriate animation style for you
} UITableViewRowAnimation;
Basically it tells the table view from which direction you want the rows/sections to be animated in/out. A little experimenting will demonstrate the effect of each.
For example, inserting a row with UITableViewRowAnimationTop will trigger an animation which gives the impression of a row coming into the table view from a space immediately above that of its final destination in the table view.
So your insertion might look like:
-(void)sliderValueChanged:(id)slider {
slide = slider.on;
[tableView beginUpdates];
if (slider.on) {
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationTop];
// TODO: update data model by inserting new section
} else {
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationTop];
// TODO: update data model by removing approprite section
}
[tableView endUpdates];
}
And you will have to be sure that your delegate and data source provide info that is consistent with your assertion to insert sections/rows. From your question, it looks like you have done so.
EDITS:
I don't think you have to call reloadData. UITableView requires that your data model reflect the changes you make with with the insert/delete methods. So that, for example, if, before a call to insertSections:withRowAnimation: (with which you are inserting a single section), your numberOfSectionsInTableView: method returned 1, then, after the call, it must return 2. To do otherwise throws an exception. It is this enforcement of consistency that allows you (again, I think) to avoid the call to reloadData - the necessary data is being reloaded by the whole beginUpdates: endUpdates: transaction, and any updates to the model you make during that transaction must match one-for-one your insert/delete calls.
Clear as mud?
UPDATES
If you were programming explicit animations, then I would say that you could do it in the 'completion handler' (or just program the animation directly for that matter), but that is not available to you here. I think you can wrap the button-presenting code in its own method in the view, then set a timer to call it after a short amount of time, say, .2 seconds (you'll have to experiment to see what looks good). e.g.
[NSTimer scheduledTimerWithTimeInterval:.2 target:self selector:#selector(presentButton) userInfo:nil repeats:NO];
That should do the trick.
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
This method pointed out by will definitely do the magic.
Probably you can try this:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
Writing straight out of my mind.. hope this helps...
Please note:
Any of the UITableViewRowAnimation can be used.
sectionIndex in the mentioned code is an NSInteger. Probably in your case 1.

Resources