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
Related
This cool expanding tableView works great but when you select some of the rows, a weird animation occurs.
The table has multiple sections, and each row can show additional rows when clicked. Row appearance and behavior is structured in a plist using various values e.g. if a row's boolean "isExpandable" property in the plist is set to true and its "additionalRows" property is set to 2, the row can expand to show 2 sub-rows.
The issue with the table is that when the first cell in each section is clicked, the animation runs fine, but when other cells are clicked, they shuffle:-
I suspect the strange animation happens because all sections are reloaded when a cell is clicked because of this line under didSelectRowAtIndexPath in the ViewController file:-
tbl.reloadSections(NSIndexSet(index: indexPath.section), withRowAnimation: .Automatic)
I've tried the following but they either crash the app or cause the cells to not expand:-
Setting the animation method to .None
Using reloadData instead
Storing the indexPaths of the selectedRow and its sub-rows, and then reloading all with reloadIndexPaths
Storing the rows of the selected cell and its subcells then reloading them once when a row is clicked
Someone on the actual site that the code is posted on suggested using insertRowsAtIndexPath and deleteRowsAtIndexPath instead of reloadSection, but I'm not sure how to do it. Your help is greatly appreciated.
EDIT
- Also tried insertRowsAtIndexPath and deleteRowsAtIndexPath but it seems to conflict with the way the tableView model is set up and the app crashes.
Inserting rows into the table should help you with more consistent table view animation behaviour.
To insert rows at specific index paths you can use the 'insertRowsAtIndexPaths' method. You will need to generate each index path that you are inserting and then pass them to the method in an array.
ObjC:
NSArray* arr = your NSIndex Paths...;
[tableView insertRowsAtIndexPaths:arr withRowAnimation:UITableViewRowAnimationFade];
Swift:
table.insertRowsAtIndexPaths([IndexPaths..], withRowAnimation: .Automatic)
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/insertRowsAtIndexPaths:withRowAnimation:
Here is the problem: reloadSections(..) makes the tableView conveniently fetch all of the newest data from the model (for the specified section(s)) at the cost of more 'vague' animation. Use insertRowsAtIndexPaths(..) with the .Top animation style for the behavior you are looking for. If you have issues with your Data Model, fix that first (because it will almost certainly bother you later).
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.
I'm not quite sure what's going on here but I'm running into a contact form that I'm working with. In my form I've added the ability to add an email address to a contact. As pictured below, once the user clicks on "add email", a row is added to the "Emails" section.
However after I click to delete the email, an extra cell appears underneath the add email button (pictured below).
There's a little red box from what appears to be the prior delete cell as though the table isn't reloaded. Here's my delete code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if( editingStyle == UITableViewCellEditingStyleDelete )
{
// Update the data source
NSMutableArray *fields = (NSMutableArray *)self.fields[#(indexPath.section)];
[fields removeObjectAtIndex:indexPath.row];
NSMutableArray *values = (NSMutableArray *)self.values[#([self fieldTypeAtIndexPath:indexPath])];
[values removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
}
}
So why is that cell remaining afterwards? I can call [tableView reloadData] within the method above and it removes the excess cell but then it messes up the animation. Can you shed some clarity on what I'm doing wrong here?
This looks like a bug.
I just noticed that even Apple has this same bug in their Reminders app. It seems to be related to deleting rows from a UITableView with variable height items.
In Apple's Reminders app, when you delete something from a long list with variable height items, you will see the same exact visual artifact for a split second. Then the table jumps and the list looks correct. I am assuming Apple just reloads the entire table view a second after the item is removed in order to fix the visual glitch.
My recommendation is to report this as a bug to Apple. For now you can reload the entire table view like Apple presumably does.
Option 1: Before you call deleteRowsAtIndexPaths, you must make sure that numberOfRowsInSection will return the correct value (e.g. if you originally had 2 rows in that section, it should now return 1 row).
Option 2: If that isn't the problem, I would try a different animation type (e.g. UITableViewRowAnimationAutomatic), just to see if that has any effect.
Option 3: Ensure that cellForRowAtIndexPath is returning a valid cell with its contents being reset. Otherwise it may be reusing an invalid cell or displaying something that was there before.
Option 4: Since the heights are different, ensure that heightForRowAtIndexPath is returning the correct value. You probably need to call reloadRowsAtIndexPaths in order for the table view to know about the height difference.
I had the same problem and I guess it might be a bug in iOS7 where it doesn't repaint the cells correctly, I fixed it but not in an efficient way, just in the "cellForRowAtIndexPath" , always create a new cell, don't dequeue it.
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.
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