Add/Delete UITableViewCell with animation? - objective-c

I know this might sound like a dumb question, but I have looked every where. How can I do this?
I know how to do this with a swype-to-delete method, but how cam I do it outside that function?
Please post some code samples.
Thanks!Coulton

[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
insertIndexPaths is an array of NSIndexPaths to be inserted to your table.
deleteIndexPaths is a array of NSIndexPaths to be deleted from your table.
Example array format for index paths :
NSArray *insertIndexPaths = [[NSArray alloc] initWithObjects:
[NSIndexPath indexPathForRow:0 inSection:0],
[NSIndexPath indexPathForRow:1 inSection:0],
[NSIndexPath indexPathForRow:2 inSection:0],
nil];

In Swift 2.1+
tableView.beginUpdates()
tableView.deleteRowsAtIndexPaths([YourIndexPathYouWantToDeleteFrom], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([YourIndexPathYouWantToInsertTo], withRowAnimation: .Fade)
tableView.endUpdates()
And you can create an NSIndexPath easily like so:
NSIndexPath(forRow: 0, inSection: 0)

You want these two methods: insertRowsAtIndexPaths:withRowAnimation: and deleteSections:withRowAnimation: They are both detailed in the UITableView documentation.

Swift 4.0
tableView.beginUpdates()
tableView.deleteRows(at: [YourIndexPathYouWantToDeleteFrom], with: .fade)
tableView.insertRows(at: [YourIndexPathYouWantToInsertTo], with: .fade)
tableView.endUpdates()
For creating IndexPath use this:
IndexPath(row: 0, section: 0)

Related

iOS - deleting row from UITableView doesn't animate

I have a very frustrating issue. I have an app with a UITableView.
When I am removing a cell from the table view, it is removed from the data model and then I call the following:
-(void)removeItem:(NSIndexPath *)indexPath {
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
}
My problem is, I've tried it like I do above, and I've tried without using animateWithDuration. I've even tried with a CATransaction, but however I do it, the animation doesn't happen.
I've got slow animations on in my Simulator and when I remove an item from the list, it removes correctly, but without animation.
It just disappears and leaves a blank space for a moment before the table view data is reloaded.
I've search all over SO and Google and I can't seem to find an answer.
Any ideas?
Does it perhaps have to do with the fact that I'm removing the object from the data model before calling the function above?
Edit: Removed the Animation Block as it is incorrect
According to THIS you don't need to use the animateWithDuration:animations: at all.
Just try it like this
-(void)removeItem:(NSIndexPath *)indexPath {
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
}
Okay, I don't know if it's just bad manners, but I feel I'm going to answer my own question here.
First, thanks for all the other answers, you were all correct of course, but none of the answers solved my problem.
It turns out that there is another area in the code that does a different check then calls one of the tableView delegate methods, that seems to cancel the animation.
So the answer is as follows:
When you're row is removing but the animations aren't working, make sure that you are not calling didSelectRowAtIndexPath:indexPath before the animation starts. This will cancel the animations.
If you're NOT having that problem, here's some really typical code for expanding, two lines in the example:
Note that facebookRowsExpanded is a class variable you must have:
if ( [theCommand isEqualToString:#"fbexpander"] )
{
NSLog(#"expander button......");
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSArray *deleteIndexPaths;
NSArray *insertIndexPaths;
facebookRowsExpanded = !facebookRowsExpanded;
// you must do that BEFORE, not AFTER the animation:
if ( !facebookRowsExpanded ) // ie, it was just true, is now false
{
deleteIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:2 inSection:0],
[NSIndexPath indexPathForRow:3 inSection:0],
nil];
[tableView beginUpdates];
[tableView
deleteRowsAtIndexPaths:deleteIndexPaths
withRowAnimation: UITableViewRowAnimationMiddle];
[tableView endUpdates];
}
else
{
insertIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:2 inSection:0],
[NSIndexPath indexPathForRow:3 inSection:0],
nil];
[tableView beginUpdates];
[tableView
insertRowsAtIndexPaths:insertIndexPaths
withRowAnimation: UITableViewRowAnimationMiddle];
[tableView endUpdates];
}
// DO NOT do this at the end: [_superTableView reloadData];
return;
}
NOTE: your code for numberOfRowsInSection must use facebookRowsExpanded
(it will be something like "if facebookRowsExpanded return 7, else return 5")
NOTE: your code for cellForRowAtIndexPath must use facebookRowsExpanded.
(it has to return the correct row, depending on whether or not you are expanded.)
First, you don't need to animate the change yourself.
Second, I think you need to make the changes to the datasource between the begin and end updates.
Your method should look something like this:
-(void)removeItemAtIndexPath:(NSIndexPath *)indexPath{
[self.tableView beginUpdates];
// I am assuming that you're just using a plain NSMutableArray to drive the data on the table.
// Delete the object from the datasource.
[self.dataArray removeObjectAtIndex:indexPath.row];
// Tell the table what has changed.
[self.tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
}
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
indexPaths is an array of NSIndexPaths to be inserted or to be deleted in your table.
NSarray *indexPaths = [[NSArray alloc] initWithObjects:
[NSIndexPath indexPathForRow:0 inSection:0],
[NSIndexPath indexPathForRow:1 inSection:0],
[NSIndexPath indexPathForRow:2 inSection:0],
nil];

UITableView deleteRowsAtIndex & datasource troubles

Happy 14th Baktun everybody!
This thing has been bugging me for a while, and I've googled to and fro, and also checked SO for an answer, but I just can't seem to grasp the answers and apply it to my app. If some of you would be so kind to help out, that would be appreciated!
I got the following function that deletes a cell from an UITableView when a stepper reaches 0.
I want the cell to be animated to the left, so when you press the - sign you'll see the cell swipe out of view. I set the sender.tag to the [[cell stepper]setTag:indexPath.row]; in CellForRowAtIndexPath.
- (void)stepperChanged:(UIStepper *)sender
{
WinkelWagen *ww = [WinkelWagen sharedWinkelWagen];
BWBand *band = [ww.winkelWagenArray objectAtIndex: sender.tag];
NSDecimalNumber *nummer = [[NSDecimalNumber alloc]initWithFloat:sender.value];
band.winkelmandjeAantal = nummer;
[sender setValue:[band.winkelmandjeAantal doubleValue]];
// Remove the cell and object from WinkelWagen if stepper.value turns 0
if (sender.value == 0)
{
NSArray *deleteIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:sender.tag inSection:0],
nil];
[ww.winkelWagenArray removeObject:band];
[self.tableView beginUpdates];
[self.tableView reloadData];
[self.tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationNone];
if ([winkelmandjeData count] == 0)
{
NSArray *addIndexPaths = [NSArray arrayWithObjects:
[NSIndexPath indexPathForRow:0 inSection:0],
nil];
[self.tableView insertRowsAtIndexPaths:addIndexPaths withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates];
}
}
UPDATE:
I've worked it out with [[self.tableview]reloaddata] but then the animation doesn't play. Can someone tell me how I should handle the data and the animation properly?
Thanks!
I see there something you could have a problem with, but don't know if it is an answer to your question. In your if ([shoppingCartData count] == 0) you are adding a row to the table, but the data source remains the same. That could result in a crash.
Also, before the if, your data source seem to be ww.shoppingCartArray, but in the if you are checking the count of shoppingCartData.
Hope this helps!

Select uitableview row programmatically

i have read a lot on this argument, i have tested this example that works:
source code example. but this doesn't use storyboards (i don't know if this is the reason that make my project not working)
i have made another project using storyboard, the same sequence of instruction doesn't work...
-(void)viewDidAppear:(BOOL)animated{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
[firstController.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[firstTable.delegate tableView:firstTable didSelectRowAtIndexPath:indexPath];
}
here is my project, is the same of the previous link, only adding viewDidAppear
my not working project
can someone tell me what's wrong?
thanks
I tried to study your code downloading the project.The problem is that firstController.tableView is nil.
So fix it:
[firstTable selectRowAtIndexPath:indexPath
animated:NO
scrollPosition:UITableViewScrollPositionNone];
Or assign firstController.tableView to the table view.
- (void)viewDidLoad {
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone];
}
If you want the callback from the delegate:
if ([self.tableView.delegate respondsToSelector:#selector(tableView:didSelectRowAtIndexPath:)]) {
[self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
}

reloadRowsAtIndexPaths do nothing

I need to change the text's cell when the device rotate. This is my code:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[self.lista beginUpdates];
NSIndexPath *durPath = [NSIndexPath indexPathForRow:0 inSection:0];
NSArray *paths = [NSArray arrayWithObjects:durPath, nil];
UITableViewCell *celda = [self.lista cellForRowAtIndexPath:
[NSIndexPath indexPathForRow:0 inSection:0]];
celda.textLabel.text = #"new text for the cell";
[self.lista reloadRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationNone];
[self.lista endUpdates];
}
and nothing happens. What's wrong?

NSInternalInconsistencyException', reason: 'attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update'

I am using UITableViewController and getting this error while updating tableView. Below is my code:
This occurs when i do a click event:
[timeZoneNames insertObject:#"HELLO" atIndex:0];
[self.tableView beginUpdates];
NSArray *insertIndexPaths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
I tried looking for apple documentation but that didnt helped.
Thanks,
Aby
I ran into this error when I forgot to set the datasource outlet properly.
If you see this error, check that you have explicitly set your TableView delegate and datasource :
go to your interface builder and look at the view with the 'Table View'
cmd + right click drag ( you should see a blue line ) from the 'Table View' icon to the title icon for the file, this has a yellow icon next to it in xcode 6.
release your mouse , you should see delegate and datasource options.
select 'datasource'
your table should now be correctly wired.
I've ran into this problem before. It means that when -insertRowsAtIndexPaths:withRowAnimation: was called -tableView:numberOfRowsInSection: returned 0. You need to insert into the model before you call -insertRowsAtIndexPaths:withRowAnimation: (see: -beginUpdates)
Update
I wonder what the return value of -tableView:numberOfRowsInSection: is? Also, you don't need -beginUpdates/-endUpdates if you only have one update.
[timeZoneNames insertObject:#"HELLO" atIndex:0];
// Let's see what the tableView claims is the the number of rows.
NSLog(#"numberOfRowsInSection: %d", [self tableView:self.tableView numberOfRowsInSection:0]);
NSArray *insertIndexPaths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationTop];
I tried printing out how many rows and sections were actually in the tableView during the update which got me thinking, how many sections am I returning in the table view data source method...and this was the culprit:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 0;
}
Make sure you are returning 1 and not 0.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
At least this solved the problem for me...
UPDATE:
I'm having the same problem again after it was working for a while. I had modified the app a bit. My first view is a tableView and when you click the plus button on the upper right, you get another table where you can input information. When you click done, the information is added to the Core Data model with this code:
- (IBAction)doneButtonPressed:(UIBarButtonItem *)sender
{
MoneyBadgeAppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
NSManagedObject *newMoment;
newMoment = [NSEntityDescription
insertNewObjectForEntityForName:#"SpendingMoment"
inManagedObjectContext:context];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyyMMdd"];
NSDate *modifiedDate = [dateFormat dateFromString: self.dateTextField.text];
[newMoment setValue: modifiedDate forKey:#"date"];
[newMoment setValue: descTextField.text forKey:#"desc"];
[appDelegate.eventsArray insertObject:newMoment atIndex:0];
NSError *error;
[context save:&error];
[self dismissViewControllerAnimated:YES completion:nil];
}
And I confirmed it gets put into the Core Data model successfully by printing to the console the following in my viewDidAppear method upon returning back to the first screen.
-(void)viewDidAppear:(BOOL)animated{
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SpendingMoment"
inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSError *error;
NSArray *items = [self.managedObjectContext
executeFetchRequest:fetchRequest error:&error];
for (SpendingMoment *moment in items) {
NSLog(#"Date: %#, Desc: %#", [moment date], [moment desc]);
}
[self addEvent];
And then my addEvent method does this:
- (void)addEvent {
[self.tableScreen beginUpdates];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableScreen insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableScreen reloadData];
[self.tableScreen endUpdates];
#try{
[self.tableScreen scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
#catch(NSException *exception){
}
}
Any idea what the problem is this time??? Thanks!
Check this "attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update".
It mesns when you insert object in row 0 , section 0, there are no any sections.
Try to insert section before you insert row.
[timeZoneNames insertObject:#"HELLO" atIndex:0];
NSLog(#"sections: %lu ",[self.downlaodTableView numberOfSections];
// insert section
[self.tableView insertSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 1)] withRowAnimation:UITableViewRowAnimationNone];
NSLog(#"numberOfRowsInSection: %d", [self tableView:self.tableView numberOfRowsInSection:0]);
NSArray *insertIndexPaths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationTop];