How can I cause action to be taken upon completion of a UITableview's animation?
I'm attempting to shrink a UITableview cell and remove a subview of the cell that's not visible after the shrinkage. To shrink the cell, I'm calling [tableview beginUpdates] and [tableview endUpdates], and changing the height of the cell as returned by theheightForRowAtIndexPath datasource method of the UITableview.
The challenge is, i need the tableview to complete shrinking so the subview is out of sight before I can remove the subview. if I put the code to remove the subview from the cell right after (or before or between) the to call [tableview endUpdates] then the subview is removed too soon (it doesn't wait for the animation) and it looks funny.
My thought is i'd like to be able to setup a callback that runs upon completion of the animation, and remove the subView in the callback
What about this?
[CATransaction begin];
[CATransaction setCompletionBlock:^{
// animation has finished
}];
[tableView beginUpdates];
// shrink the cells
[tableView endUpdates];
[CATransaction commit];
Try Using NSNotifications class. Post Notifications when something is about to happen, and later after something has happened. You can use a bool in the same notification method to toggle between 'about to happen' and 'has happened'.
Related
I have a tableviewcell, that on tap, grows in size, height wise, by updating the frame.
The problem is, the cells below don't adjust, move down to make it visible underneath, and the select row events are still based on the old sizes, before tap. I am using Facebook POP - which is handling animation, so tableview.beginUpdates() is out of the question, maybe?
You cannot manually update the frame of a UITableViewCell by changing its frame or bounds. Instead, you need to change the value returned by -tableView:heightForRowAtIndexPath: for that indexPath and then perform:
[self.tableView beginUpdates];
[self.tableView endUpdates];
This will cause the tableView to recalculate the heights of all the rows.
First, you need to make sure that you return the new height in heightForRowAtIndexPath, then you need to make the tableview update the cell. If you don't care about animation just call [tableview reloadData]. If you want animation you need to call [tableview reloadRowAtIndexPath: indexpath_of_your_cell]
I am using a table view as an expandable list view.I am using section as parent and cells as child.I am getting list view perfectly but the issue is that i want the expanded section view to come into view if the section at end of the screen is clicked. Currently it expands and stay there so one has to scroll it manually.
Thanks.
The easiest way to do that is to call
-[UITableView scrollToRowAtIndexPath:atScrollPosition:animated:]
But be careful. If you call that right after inserting rows for the section, the animation can look pretty bad (cells flying in from weird locations etc.) The easiest solution to that, is to do that after the row insertion animation is completed. Unfortunately, there is no callback for that and the easiest workaround is to use CATransaction callback like so:
// CATransaction is used to be able to have a callback after rows insertion is finished.
// This call opens CATransaction context
[CATransaction begin];
// This call begins tableView updates (not really needed if you only make one insertion call, or one deletion call, but in this example we do both)
[tableView beginUpdates];
// Insert and delete appropriate rows
[tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationAutomatic];
// completionBlock will be called after rows insertion/deletion animation is done
[CATransaction setCompletionBlock: ^{
// This call will scroll tableView to the top of the 'section' ('section' should have value of the folded/unfolded section's index)
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:NSNotFound inSection:section] // you can pass NSNotFound to scroll to the top of the section even if that section has 0 rows
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
}];
// End table view updates
[tableView endUpdates];
// Close CATransaction context
[CATransaction commit];
If you do the folding/unfolding without animation, for example using plain -[UITableView reloadData], you can safely call
-[UITableView scrollToRowAtIndexPath:atScrollPosition:animated:]
directly after -[UITableView reloadData]
like so:
[tableView reloadData];
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:NSNotFound inSection:section] // 'section' is the index of the section you want to be scrolled to the top of the screen
atScrollPosition:UITableViewScrollPositionTop
animated:YES];
It has been suggested that one scroll to the desired row in viewWillAppear, but this does not work with iOS 7. I have only been able to make this work in iOS 7 in the viewDidAppear callback. Unfortunately, you see the desired row scroll into view. I don't want to see any scrolling, I simply want the row to be visible when loaded. Can anyone suggest the proper way to do this in iOS 7?
It probably did not work in viewWillAppear, because that table had no data at this point.
Add [tableView reloadData];and it should work.
Let me get this straight: you want your table view to show a certain row at the top when the view apperas? Yes?
If so, you want:
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated
with your cell indexPath, UITableViewScrollPositionTop as scrollPosition and animated NO like so
[tableView scrollToRowAtIndexPath:myExampleindexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
If you know the cell index then it's as simple as:
[tableView setContentOffset:CGPointMake(cellLocation.x,cellLocation.y) animated:NO];
Call that just after you load your tableView data and it will scroll to your cell being on top. There are other options as well:
[tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:currentRow inSection:currentSection] animated:NO scrollPosition:UITableViewScrollPositionTop];
Use this code with whatever scrollPosition you would like and Apple takes care of the bounding to the table (whereas setting the scrolling position is all user defined, it could be out of the table's view).
EDIT:
You could surround your selecting code with a call to UIView setting no animations allowed. That has worked for me in the past with different things, but I have never tried it in viewDidLoad.
[UIView setAnimationsEnabled:NO];
//Scroll the tableview
[UIView setAnimationsEnabled:YES];
I have a UITableView, its cells' height can be either 68pt or 78pt. For example there are two 68pt height cells and one 78pt. I add new object to the datasourse and then call -reloadData to refresh the UITableView. But when this method fires - appears animation of one cell height change and I'd like to switch it off.
Due to some limitations I can't use [tableView beginUpdates] and [tableView endUpdates].
Try:
[UIVIew setAnimationsEnabled:NO];
[tableView reloadData];
[UIView setAnimationsEnabled:YES];
to see if this is what you want. (animations in UIView are enabled by default)
I have a table with shadows above the top and below the bottom cell (using Matt Gallagher's solution here: http://cocoawithlove.com/2009/08/adding-shadow-effects-to-uitableview.html). These are added in the layoutSubviews method of the UITableView class extension.
I dynamically add and delete cells below each main cell (these provide additional data) - let's call these "detail" cells. There is only one ever open at a time. When deleting the "detail cell" beneath the last main cell, as the animation begins, the shadow flicks upwards to the last cell (above the detail cell). It does this because the layoutSubview methods considers the last cell of the table to have changed the moment the animation for deleteRowsAtIndexPaths begins (rather than when the animation ends).
So, in essence, I need a way to keep the shadow below the detail cell as its being deleted. Not sure of the best way to do this. If the UITableView no longer considers that cell to be the last cell, then I am not sure even how to get the cell (since the UITableView gets the cell thus):
NSIndexPath *lastRow = [indexPathsForVisibleRows lastObject];
if ([lastRow section] == [self numberOfSections] - 1 &&
[lastRow row] == [self numberOfRowsInSection:[lastRow section]] - 1)
{
//adds shadow below it here
}
So even trapping the start of the animation is not much use if the UITableView still thinks the main cell above the "detail" cell is the "lastObject".
Thanks for any ideas.
Try this
[CATransaction begin];
[tableView beginUpdates];
//...
[CATransaction setCompletionBlock: ^{
// Code to be executed upon completion
}];
[tableView deleteRowsAtIndexPaths: indexPaths
withRowAnimation: UITableViewRowAnimationAutomatic];
[tableView endUpdates];
[CATransaction commit];
I am sure that you can easily achieve this by using a custom table view class instead of using dependencies from external frame work just inherit from the uitable view and add subviews to it.
But if you insist to keep it this way. take a reference in your own variable before deleting it.
Swift (the idea is the same, you can of course use this in obj-c):
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.tableView.scrollToRowAtIndexPath(indexPathes, withRowAnimation: UITableViewRowAnimation.None)
}, completion: { (Bool) -> Void in
// The logic you want to execute after the animation
})