Partially-rendered UITableView header - ios

I am populating a UITableView from an array - lets call it sections. The numberOfSectionsInTableView returns sections.count, except for a special case - if sections.count is 0, I return 1 (1 is the minimum number of sections that should ever be returned by numberOfSectionsInTableView). I return nil as the section header in this case, so the UITableView looks empty.
When a new item is added to my dataSource, I manually insert a new row. I also check if a new section is required, and if so I add it to sections and insert the new section. But here is where my 'special case' causes problems.
When adding the first item, to the first section, I don't want to add a new section (because there is already one section minimum at all times). So, I just insert the row.
The row animation insertion seems correct, but I get a strange half-loaded header:
All I really need to do is make the UITableView reload the header when the first row is inserted. But I don't want to lose the insertion animations by simply reloading the tableview or the section.
Any ideas?

I think that you are looking for -reloadSections:withRowAnimation:.
After you add or remove the special case of section 0, you can call:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
Hope that helps.

Related

How to animate the removal/addition of tableView cells when using multiple sections while the number of sections has the possibility of changing

So I have a UITableView with many sections, each section contains items with a certain letter of the alphabet(Alphabetically sorted). The user has the ability to add more data to this table, so when they add a new item that goes in a section that is not there, a new section must be created. Same problem when deleting, if the last item in a section is deleted the whole section would be removed. How would I animate this?
I have found something similar to this: UITableview reloaddata with animation
But that does not help me. It recommends using this method(In swift):
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
This works great if you have the same number of sections before and after the reload, but mine does not. The number of sections could change causing a crash.
For the purpose you mentioned above, you should not reload data. For adding the new section you should use,
- (void)insertSections:(NSIndexSet *)sections
withRowAnimation:(UITableViewRowAnimation)animation
For deleting the section you should use,
- (void)deleteSections:(NSIndexSet *)sections
withRowAnimation:(UITableViewRowAnimation)animation

UITableView: new row added to the top

Then, I would like the user to enter what he is thinking, like notes or reminds and these are displayed on a UITableView... and in my TableView I want the TableViewCells to be added at the top of the TableView. Currenty, the rows are added to the bottom of the TableView: I searched some questions already answered but any of the given answers are working...
Does anyone could help me to solve that?
Ok so hopefully I have got what you are after correctly:
User posts notes and then these get inserted in rows at the top of the table?
So there are always three parts for both inserting and deleting rows. First you need to insert the row, then insert the information into your tableView data source and then refresh.
Use to insert the cell you want at the exact indexRow you want it, in this case you want it at the top so use indexPath row and section as 0.
[self.tableView insertRowsAtIndexPaths:[NSIndexPath indexPathForRow:0 inSection:0]; withRowAnimation:UITableViewRowAnimationFade];
Next you need to insert it into your data. I usually use a mutable array so just insert the object at the correct index again:
[_tableViewData insertObject:text atIndex:0];
Then refresh the tableView:
[self.tableView reloadData]
This should be a pretty straight forward thing to achieve, making sure you get it in the right order and that your datasource stays correct is the trickiest thing as this will cause crashes.
Hope this helps

Inserting cell to top of uitableview causes problems

This is driving me nuts, I have sections in my UITableView, but this insertion works when I don't have sections.
Basically I'm doing:
[self.tableView insertRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationRight];
I'm getting this error:
The number of sections contained in the table view after the update (5) must be equal to the number of sections contained in the table view before the update (4), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).'
I thought it would just work, but this doesn't make sense. What can you guys make of this?
You are returning different values from your numberOfSectionsInTableView: method before and after you send the insertRowsAtIndexPaths:withRowAnimation: method.
If you are creating an entirely new section in the table view, you must insert it by sending insertSections:withRowAnimation: message to the table view.
Whenever you make a insertRowsAtIndexPaths:withRowAnimation call, you also need to modify the data source that backs the table with a similar addition. This ensures that tableView:numberOfRowsInSection: returns n before the addition and n+1 after the addition. Anything besides a consistent result with throw the error you described.

UITableView's reloadRowsAtIndexPaths: seems to break insertRowsAtIndexPaths:

I have a UITableView into which the user can insert new rows. When this happens, I want to reload all of the old rows in the table. One solution would be to just call reloadData as soon as the insertion takes place, which totally works, but this means I don't get the insertion animation.
So when the user hits the "add row" button, I call reloadRowsAtIndexPaths: with every index path except the one just inserted. Then I call insertRowsAtIndexPaths: with only the newly inserted row. Reasonable, right?
This causes the app to crash with the following explanation:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
This happens, as you can see in this example, even when reloadRowsAtIndexPaths is passed an empty array of index paths.
Ah! I need to wrap the two calls with beginUpdates and endUpdates. Fair enough. But now the animation is completely broken.
I'm performing the reload with a UITableViewRowAnimationFade and the insertion with a UITableViewRowAnimationAutomatic. But during the animation, the heights of every row changes, creating this weird flickery effect that looks just terrible. What's the correct way to animate these changes?
Edit:
From the docs for reloadRowsAtIndexPaths:withRowAnimation::
Reloading a row causes the table view to ask its data source for a new cell for that row. The table animates that new cell in as it animates the old row out. Call this method if you want to alert the user that the value of a cell is changing. If, however, notifying the user is not important—that is, you just want to change the value that a cell is displaying—you can get the cell for a particular row and set its new value.
I think that, in my application, manually updating each cell is the right way to go. However, I am still perturbed by this bizarre animation bug, and would like to know what the cause of it is / what I would do if I did "want to alert the user that the value of the cell is changing."
A common reason for getting that error is, as the docs say, the datasource is asked for a cell. It might be less clear that it is asked twice...once to provide the initial data, again to provide the final data. That implies that the tableView:numberOfRowsInSection: method must return the old values before beginUpdates and the new values after endUpdates (or if you're using a shortcut method, before and after the call). Don't forget about numberOfSectionsInTableView either if it is relevant.
Example:
numberOfRows... return [array count];
// Incorrect
[array addObject:object];
[tableView beginUpdates];
[tableView insertRow..];
[tableView endUpdates];
// Correct
[tableView beginUpdates];
[array addObject:object];
[tableView insertRow..];
[tableView endUpdates];
For your specific case, I would recommend doing the insertion, then calling reloadData on the whole tableview so long as that doesn't mess up your animation or anything else.
You don't need to have any operations with exactly cells. All what you need - is change your datasource array, then call reload data/row/section, and you'll get changed data in your table view, with added rows.

UITableView reloadRowsAtIndexPaths performing animation when it shouldn't

I'm using a UITableView in my iOS app, and have been seeing a strange issue recently.
Suppose my table is structured as follows:
section 1 header
row
section 2 header
section 3 header
row
row
...
(Note that section 2 has no rows)
I'm performing updates to the rows in my table via
[self.tv beginUpdates];
[self.tv reloadRowsAtIndexPaths:ip withRowAnimation:UITableViewRowAnimationNone];
[self.tv endUpdates];
I don't want any animations taking place. I just want the row to update. The issue is that this strategy works for every row and section in the my table except section 3, row 1: the first row of the last section. When I update this row (which is indeed using the correct indexPaths), rather than get no animation, the row does this little jump, like it's sliding in a new row to replace the old one or something. The row slides up ever so slightly, then back down, as if I was inserting a row. I'm guessing it has something to do with the header calculations, but I do return correct values for heightForHeaderInSection.
Has anyone seen this behavior?
I wonder if the beginUpdates and endUpdates are necessary in this reload only scenario.
I had the same problem. The solution was to fetch the cell from the table using:
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]
and then refresh it manually using a custom setup method or by simply calling:
[cell setNeedsLayout]
For more info, see:
UITableView reloadRowsAtIndexPaths graphical glitch

Resources