Programmatically move/animate a UITableView row from one position to another - iphone

I have a UITableView and I want to programmatically move one row from position N1 to position N2 and I would like it to animate from the old location to the new. I've looked through the UITableView documentation and I'm only seeing inserts, reloads, and deletes. Do you know of a way I can do this programmatically?
A couple of notes:
I know that I can animate the deletion from location N1 and animate the insertion to location N2 at the same time. That's my fallback, but I'd like the user to understand that it is truly moving from N1 to N2.
I'm not talking about allowing the user to drag it from one place to another. I understand how to do that, I'm looking for a way to initiate and animate the move programmatically.

I've dealt with something kind of like this in the past and the solution is not pretty but it does work.
Basically you have to do some math to calculate where on the screen the row is. Then adjust that based on the y property of the contentOffset of your UITableView.
You can do that like this:
[myView convertPoint:localPosition toView:nil];
Then you would construct a new UIView that's identical to your view. Set its frame to be directly on top of the UITableViewCell you're trying to move. Add it as a subview of your app's main UIWindow.
You'll want to set userInteractionEnabled or scrollEnabled to NO on your UITableView while all of this is going on so that the user can't muck with the position of things throughout the process (just remember to set it back to YES when everything is done animating).
Then animate it to the new position however makes the most sense.
I understand you may have to scroll the UITableView in the process of all of this, which complicates things considerably, but you can animate that scrolling as well.
You'll of course have to do similar operations on the row you're animating to if it is necessary in your app.
Like I said its not easy or pretty. But I do understand what you're trying to accomplish and I think the effect is super awesome when it's pulled off properly.
If anyone has a better idea of how to pull this off without going insane I'd love to know, but this type of implementation is the best I've been able to do.

[table beginUpdates];
[table moveRowAtIndexPath:indexPath toIndexPath:destIndexPath];
[table endUpdates];

If you're using iOS 5 or hight you could use the method:
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
For example:
//move last cell one row up.
NSIndexPath *oldPath = [NSIndexPath indexPathForRow:[items count] - 1 inSection:0];
NSIndexPath *newPath = [NSIndexPath indexPathForRow:[items count] - 2 inSection:0];
[[self tableView] moveRowAtIndexPath:oldPath toIndexPath:newPath];
Check out apple's documentation here.
I guess your best fallback would indeed be the deletion and insertion method, something like:
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:oldPath] withRowAnimation:UITableViewRowAnimationLeft];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newNewPath] withRowAnimation:UITableViewRowAnimationLeft];
[tableView endUpdates];

Related

Getting NSIndexPath of a row for UISwitch

I have a tableview with custom UITableViewCells, each row in the table has a UILabel, UISwitch and detail disclosure indicator.
I'm looking for the best method of capturing the UIControlEventChanged for the switch but I also need the NSIndexPath of the switch that changed to update Core Data.
I don't want the UISwitch as an accessory type either.
I've been googling this for hours and the solution that keeps popping up is to use
[switch addTarget:self action:#selector(switchTapped:) forControlEvents:UIControlEventChanged];
then in the switchTapped: method use the following to get the NSIndexPath
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
Is there a better way of doing this? I already have UITableViewCell subclassed, can I put a method in this class to return the NSIndexPath for a given switch?
Thanks in advance for any help
I'll take another opportunity to link to my answer here - tags and view hierarchy walking are clunky, error prone and unnecessary, and I see them recommended all over the place in SO answers. You can find the index path of any control using its frame and the table view's indexPathForRowAtPoint: method.
Setting a proper tag for the switch in each row of the table is a feasible solution. Set the tag according to the indexpath of the row in which it is present.
That way you avoid the possible problems that might arise to changes in view hierarchy.
This post might also help you.

How do I add or remove an off-screen row at the top of a Table View without scrolling?

I have a UITableView containing a list of items.
When the user taps the Edit UIBarButtonItem, the top row needs to be removed, because it is not editable.
I do that like this:
- (void) setEditing: (BOOL) editing animated: (BOOL) animated
{
if (editing)
{
[self.theTableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: [NSIndexPath indexPathForRow: 0 inSection: 0]] withRowAnimation: UITableViewRowAnimationTop];
// call super afterward so the user doesn't see the row get an editing accessory before it disappears
[super setEditing: editing animated: animated];
}
else
{
[super setEditing: editing animated: animated];
[self.theTableView insertRowsAtIndexPaths: [NSArray arrayWithObject: [NSIndexPath indexPathForRow: 0 inSection: 0]] withRowAnimation: UITableViewRowAnimationTop];
}
}
This code (unrelated bits snipped) works just fine, with one caveat:
If the user is anywhere but at the top of the table (assuming there is more than a single screenful of row), the animation behavior causes the entire table view to scroll up (or down), and the behavior of the last row in the table is, at best, usable.
My question: How can I only make the top row animate out when the user can see it, but when the user can't see it, it just disappears, but does not cause the table to scroll.
Have you tried UITableViewRowAnimationBottom instead of UITableViewRowAnimationTop?
Otherwise you can manually set the contentOffset property of the UITableView to adjust for the missing row.
Try using UITableViewRowAnimationRight. That should make the cell slide out if it's visible, but otherwise leave your table intact.
Before you do the animation check if the first row is visible.
If yes, peoceed.
Else, you want it not to appear when the user scrolls up, right? so replace the table's data source with one without the first row and after editing ends return the first row to that data source.
Another option might be not displaying it by manipulating
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
But that is probably a bad practice.
There doesn’t appear to be any simple solution to this. I’ve had limited success with completely custom behavior in a UICollectionView, but major versions of iOS and years later, even Apple’s own built-in apps continue to get this edge case wrong.

How to auto-scroll UITableView?

I am trying to do something interesting.
I am pulling some JSON data and populating cells in a UITableView. How can I make the UITableView scroll ever second or so? I want to give the effect that as new data is coming in, the table is scrolling, so it is streaming.
Any ideas?
Yes, use scrollToRowAtIndexPath:atScrollPosition:animated:.
You could also use UIScrollView's scrollRectToVisible:animated: if you want to have more finegrained control and can calculate exactly what your scroll position should be in pixels. (UITableView is subclass of UIScrollView.)
But if you are just adding cells, sounds like you could also just use insertRowsAtIndexPaths:withRowAnimation:, this is also "interesting."
Just do this
[table reloadData];
NSIndexPath *myIP = [NSIndexPath indexPathForRow:[arrayIn count]-1 inSection:0] ;
[table scrollToRowAtIndexPath:myIP atScrollPosition:NULL animated:YES];
in anywhere where arrayIn is your array by which your table populate.
you can use uitableviews scrollToRowAtIndexPath to do this....heres a link reference
You can call this method whenever as youd like to scroll your tableview
And you can call performSelector:withObject:afterDelay: for the timer effect - although if you are really pulling in data every second, it's best to just reloadData as you go.

VERY weird UITableViewController.tableview behaviour on scrollToRowAtIndexPath

hey all, I'm very confused here, i've been trying to figure this one out. I have a UIViewController, viewControllerBrowse, with two TableViewController, Designations & Types, I call a second UIViewController, viewControllerSelectLibrary, that makes some SOLite operations and fills two arrays from where the first two TableView feed.
When I'm going to call back viewControllerBrowse, I perform inside a NSThread:
[appDelegate.viewControllerBrowse.tvcTypes.tableView reloadData];
[appDelegate.viewControllerBrowse.tvcTypes.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];
[appDelegate.viewControllerBrowse.tvcDesignations.tableView reloadData];
[appDelegate.viewControllerBrowse.tvcDesignations.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];
What TRUUUULY puzzles me is that on tvcTypes case, its tableView gets its first row selected and scrolled to the top
BUT, for tvcDesignations, its tableView get ITS FIRST ROW SELECTED BUT IT DOES NOT SCROLL TO THE TOP
the fact that the first row is selected tells me that it's not a problem of reference in the appDelegate, it's as if only half the method is working/??????????????
anyone hit this one before??????
Just a guess, but what happens if you pass NO to animated? I've never seen this behavior specifically, unfortunately, but I have seen some animations cause weird interactions.
Also, which view controller is visible? Either of them?

UISegmentControl and UITableViewController animation

How can I animate my "removal of tableviewitems" when the user changes between segments in the UISegmentControl?
The behaviour should be similar to "Missed/All" calls in the Phone App.
The deleteRowsAtIndexPaths:withRowAnimation: and insertRowsAtIndexPaths:withRowAnimation: will provide the animation for you.
If you need to perform a more complex operation (inserts and deletes), you start a block. similar to a UIView animation block:
[tableView beginUpdates];
//add and delete
[tableView endUpdates];
Bear in mind you will need to update the model to reflect the changes in the table.
UITableView can be sent a message: deleteRowsAtIndexPaths:withRowAnimation:
The withRowAnimation argument determines the type of animatio that will be used in removing the cell.
I don't know if any of those animations match the missed/all functionality exactly though. If they don't, I'm guessing you will have to set up an animation to collapse the height of the cells before removing them.