How to make a slide in UIViewTableCell - ios

I am trying to create a UITableView so that When the user touches my normal UIViewTableCell another UIViewTableCell slides in from the right side with a new cell format. This new UIViewTableCell does not leave the UITableView.
The UIViewTableCells are 2 different custom Cells.
I was wondering if there is a way to swap one UITableViewCell that is of X type for another UITableViewCell that is of Y type with an animated sliding effect?
I've looked at the following code but I do not understand where do I place my Cell information.
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:myIndexPaths
withRowAnimation:UITableViewCellRowAnimationRight];
[tableView endUpdates];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:myNewIndexPaths
withRowAnimation:UITableViewCellRowAnimationLeft];
[tableView endUpdates];
Any guidance on how to do this is highly appreciate it.
PS: I am not looking for a repo. I would like to understand how this is done.

Basically the way table view cell animation works is you update your data source (usually an array that you reference when providing cells to the table view), then call the animation methods. The table view calls numberOfRowsInSection and cellForRowAtIndexPath when you insert a cell, so it's important that they return the correct values.
In this situation, however, the number of cells remains the same so you can't use insertion and deletion. You can use cell reloading, however. Theoretically, every time didSelectRowAtIndexPath is called you would add to a list of tapped index paths that should display the new kind of cell. Alternatively, if you only want one of these special cells present at a time, you would use a single NSIndexPath variable. Then you would call
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationRight]; //or left
Then, in cellForRowAtIndexPath, you would check to see if the particular row requires a different type of cell, and you would return that new type there. That way, the code you need to present the new type of cell is insulated from the initializing of the new cell.
Hope this works for you!

Related

iOS : How to reload a UITableView with a lot of cells without lagging the App?

I have a lot of cells (around 3000 cells) that I need to reload constantly. I was wondering if there is currently a way to reload it faster without it lagging the App. I do the typical [tableview reloadData]; Any tips or suggestions are appreciated.
Don't implement tableView:heightForRow: in your delegate or it will slow down considerably as it recalculates every row. iOS checks to see if you implement that method and if you define it the OS changes its table height calculation from a simple multiply to a loop over the cells.
Since you have not provided context or code to show where you call [tableview reloadData];, I can only talk in generalities.
I am going to assume in your 3,000 rows possible 20 are displayed at a time.
Here is the sequence of events or actions that needs to occurs
A row gets update
Check if row is visible: indexPathForVisibleRows
If row is not visible, nothing to do
If row is visible, then following actions should be taken
[tableview beginUpdates]
[tableview reloadRowsAtIndexPaths...]
[tableview endUpdates]
Reload only visible cells if you have consistent number of items, otherwise use insert/delete methods to add cells to tableview.
When making a reloadData for your tableView, tableView:heightForRow: delegate function make a height recalculation of every row.
My solution is to save the heights for your cells already calculated (create an NSDictionary that contains all row heights. exp. create a NSDictionary with keys is the id of object that will be show on the cell and the value is the height).
When tableView attempt to recalculate the height of each cell, it will check if we have already a saved entry in your dictionary with this key (id of object), and tableView:heightForRow: will return this value if found.
I am using this solution in my chat app, and I noticed a performance increase.
Good luck.

insertRowsAtIndexPaths with 2 animations

I am currently inserting cells in my UITableView with the following code:
[rottenTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationTop];
It does the job correctly with the animation UITableViewRowAnimationTop. However, I would like to insert the cells with 2 animations at the same time (UITableViewRowAnimationTop and UITableViewRowAnimationFade). I tried the following:
[rottenTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:(UITableViewRowAnimationTop|UITableViewRowAnimationFade)];
This code does not seem to animate insertion any differently than before. Any way to perform both animations?
As far as I know, when you use -insertRowsAtIndexPaths:withRowAnimation: there could be only one animation type for a single cell simultaneously. But I could suggest using different animation types for different cells at the same time. For this you can use batch UITableView cell's updation via using beginUpdates/endUpdates. All the animations will fire at the same time, you can use it like this:
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:insertIndexPaths1 withRowAnimation:UITableViewRowAnimationRight];
[tableView insertRowsAtIndexPaths:insertIndexPaths2 withRowAnimation:UITableViewRowAnimationOTHER];
[tableView endUpdates];
For details check this: Batch Insertion, Deletion, and Reloading of Rows and Sections.
Also check this question about custom insertion animations: Can you do custom animations for UITableView Cell Inserts?

UITableView deleteRowsAtIndexPaths not working

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.

How to add an UITextView in a resizable UITableviewCell

I need a text view inside of a resizable cell - the cell is resizing in real time, based on a specific timer/stopwatch. I can't simply put the text view inside the cell, because I'm resizing rows with reloadRowsAtIndexPath: every 10ms and that's causing the UITextView to resign first responder. I am trying to avoid calling becomeFirstResponder every time so what I did now was that I created an external text view and added it on top of the table view, so it basically only acts as if it was inside the cell.
Do you have any suggestions how else I could do this in a less hackish way?
Thanks, guys!
You shouldn't reload the table (contents) to resize. Just use:
[tableView beginUpdates];
[tableView endUpdates];
This will resize the cells but not reload the cells itself, so it should not resign the first repsonder.
[tableView beginUpdates];
[tableView endUpdates];
Call these methods if you want to perform operations simultaneously.
beginUpdates and endUpdates should be nested properly within the codes. These are the efficient methods that has been provided to us.

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