How to animate the hight change of an UITableViewCell? - iphone

In -tableView:heightForRowAtIndexPath: I'm changing the height for a cell dynamically during usage of the table. But I don't want this to happen like BAAANNGGG..., I want it nicely animated. Where would I put the animation block? Would that go just around the -reloadData call?
Well, at least this does nothing:
[UIView beginAnimations:#"foo" context:nil];
[UIView setAnimationDuration:3];
[self.table reloadData];
[UIView commitAnimations];
don't get any animation here...

Potentially the following is a better option if you're on iOS 3.0 and up:
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
Change the animation to match your preference of course...

Related

Can UIView frame be animated during UITableView update?

I have a table view with a fairly complex cell. The cell includes a button that when pressed, should expand the cell and present some extra controls. I thought this would be pretty simple, so I wrote the following code (in my class derived from UITableViewCell):
self.extraView = [[MyView alloc] initWithFrame:CGRectMake(0,100,300,200)];
self.extraView.clipsToBounds = YES;
[self addSubview:self.extraView];
self.extraView.transform = CGAffineTransformMakeScale(1, 0.1f);
[UIView animationWithDuration:0.5 animations:^{
[tableView beginUpdates];
[tableView endUpdates];
self.extraView.transform = CGAffineTransformIdentity;
}];
Surprisingly, this makes extraView flash briefly on screen and then disappear. If I remove the calls to beginUpdates and endUpdates then extraView animates exactly as I expected. However, the table cell is not large enough to display it. I tried setting alpha to 0 and then fading it in during the table update, and that seems to work fine. Unfortunately, I am supposed to make the extraView grow in place and not fade.
I have played with various ways of modifying extraView such as changing the frame, but the table updates always produce some side effect. I also tried chaining the scale change in the completion handler, which of course didn't work either. I think that is because the table view is not done animating when the completion block is executed.
Is there any way to animate the frame of a view in a cell during a table update?
It appears that the answer is no. At least, I have not found anything that will look visually correct when modifying the view frame during the table view update. What I do instead now is wait a bit and then grow the view's frame. This is how the code looks:
extraView.alpha = 0; // hide the view immediately after adding it
[tableView beginUpdates];
[tableView endUpdates];
[UIView animateWithDuration:0.5 animations:^{
button.alpha = 0; // fade out old button
} completion:^(BOOL finished) {
extraView.alpha = 1; // reappear, but not fading in
extraView.transform = CGAffineTransformMakeScale(1, 0.01f);
[UIView animateWithDuration:0.5 animations:^{
extraView.transform = CGAffineTransformIdentity; // animate scale back to original size
}];
}];
This not exactly the effect I was trying to create, but it is the closest I have been able to get. I'm posting it as the answer in case anyone else encounters a similar issue.
I had a similar issue, and wanted to open / close and change specific elements in a cell by animation based on selection.
I did this by first of all creating a subclass for the uitableviewcell.
Each tableviewcell has an open and close method which does an animation of the backgroundcolor and the size (among other things).
The open and close methods of the tableviewcell look like this:
- (void)open {
[UIView animateWithDuration:0.3
animations:^{
[self.customBackgroundView setHeight:76];
self.deleteButton.alpha = 1;
self.selectedIndicator.transform = CGAffineTransformMakeRotation(M_PI);
[self.selectedIndicator setY:60];
}
];
}
- (void)close {
[UIView animateWithDuration:0.3
animations:^{
[self.customBackgroundView setHeight:40];
self.deleteButton.alpha = 0;
self.selectedIndicator.transform = CGAffineTransformMakeRotation(0);
[self.selectedIndicator setY:24];
}
];
}
It also has a setSelected method, so when the cell is selected it opens:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if (selected) {
[self open];
} else {
[self close];
}
}
Now, only thing left, is to make sure to close other cells, when this cell is selected.
And call the tableview beginUpdates and tableview endUpdates:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_currentSelection == indexPath.row) {
_currentSelection = -1;
SOColumnTableViewCell *cell = (SOColumnTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
[cell close];
} else {
_currentSelection = (int)indexPath.row;
}
[tableView beginUpdates];
[tableView endUpdates];
}
}

Why uiscrollview doesn't make visible the contentOffset change?

Hello everyone I have a problem with a uiscrollview.
When I press a button to change the contentOffset scollview through a UIView animation so I have something like this:
NSLog(#"%#\n %f %f", scroll, scroll.contentOffset.x, scroll.contentOffset.y);
[UIView beginAnimation:#"anima" context:nil];
[UIView setAnimationDuration:0.5];
scroll.contentOffset = CGPointMake(0,index * scroll.frame.size.height;
[UIView commitAnimations];
NSLog(#"%#\n %f %f", scroll, scroll.contentOffset.x, scroll.contentOffset.y);
Making a log cotentOffSet before and after these instructions is changed and obviously the scrollview is an existing instance so it is different from nil.
The problem is that the screen does not change the offset scrollview that is not moving.
I do the same thing in other parts of the code and other scrollview but it works perfectly.
I also tried:
[scroll setContentOffset:CGPointMake(0, index * currentVerticalScrollView.frame.size.height) animated:YES] ;
but does not change too!
Why isn't it work?
Have you ensured to invoke setContentSize: on scroll originally, large enough to allow for the scroll offset?
If so, it may need a [scroll setNeedsDisplay] to give it a kick!

Can't interact with UITableView while animations are in progress

I'm trying to implement an animation that happens when a user taps one of my tableview cells. Basically, the animation is just a little label with text like "+5" or "+1" that appears, then moves upwards whilst fading (basically like points appear in video games as the user scores them).
In the tableView:didSelectRowAtIndexPath: implementation of my controller, I'm doing the following (paraphrased for simplicity here):
CGRect toastFrame = /* figure out the frame from the cell frame here */;
UILabel *toast = [[UILabel alloc] initWithFrame:toastFrame];
toast.text = [NSString stringWithFormat:#"+%d", 5];
toast.backgroundColor = [UIColor clearColor];
toast.userInteractionEnabled = NO; // hoped this would work but it doesn't
[tableView addSubview:toast];
[UIView
animateWithDuration:1.0
animations:^
{
toast.alpha = 0.0;
toast.transform = CGAffineTransformMakeTranslation( 0.0, -44.0 );
}
completion:^ (BOOL finished)
{
[toast removeFromSuperview];
}];
[toast release];
The toast is appearing nicely and looks great. The problem is that until the animation completes, the tableview stops receiving touch events. This means that for one second after tapping a cell in the tableview, you can't tap any other cells in the tableview.
Is there a way to stop this from happening and allow the user to keep interacting with the tableview as if the animations weren't happening at all?
Thanks in advance for any help with this.
Another option may be to use animateWithDuration:delay:options:animations:completion: (untested, from the top of my head)
Take a look at the options parameter and the possible flags, defined by UIViewAnimationOptions. Included there is a flag called UIViewAnimationOptionAllowUserInteraction. This could be a solution, maybe you should try it out!
Have you tried doing it the other way? For example, after adding toast as a subview, you can do something like this:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve: UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration: 1.0];
toast.alpha = 0.0;
toast.frame.origin.y -= 44.0;
[toast performSelector:#selector(removeFromSuperview) withObject: nil afterDelay: 1.0];
[UIView commitAnimations];
and then release toast. You can try it this way and see if it works.

Animate removal of UITableViewCellAccessory

Is there any way to animate the removal of a UITableView cell accessory?
I currently am showing a UITableViewCellAccessoryDisclosureIndicator, but I would like to animate swapping the disclosure indicator with a UISwitch on all visible table cells.
I've tried something like this:
[UIView animateWithDuration:0.3
animations:^{
for (SwitchTableViewCell *cell in self.tableView.visibleCells)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}];
... but unfortunately that has no affect. The disclosure indicator abruptly disappears and the contentView width jumps in one step, rather than a smooth transition.
accessoryType is not an animatable property. There are two ways you can do this, depending on your situation. The easiest only applies if you are changing the accessory to a UISwitch because of entering the editing state. In this case, just usecell.editingAccessoryType = theSwitch; in your tableView:cellForRowAtIndexPath: method. The table view will then do a fade in/out automatically when entering editing mode.
If you are doing this outside of editing mode, then the following code will do what you want:
[UIView animateWithDuration:0.3 animations:^{
for(SwitchTableViewCell *cell in self.tableView.visibleCells) {
[[cell valueForKey:#"_accessoryView"] setAlpha:0.0];
}
} completion:^(BOOL done) {
for(SwitchTableViewCell *cell in self.tableView.visibleCells) {
cell.accessoryView = theSwitch;
}
}];
However, I do not know if this code will make it into the app store since it uses the hidden property _accessoryView.

Rotate UIImageView in UITableViewCell - iPhone SDK

I have an uiimageview in my uittableviewcell in my uitableview. What I want to accomplish is rotate all the uiimageviews of each cell using a timer. I know how the nstimer and rotating concept goes about, but I do not know how to rotate ALL the images in EACH cell in the UITableView. Is there a way to have access to these properties of all the uitableviewcells?
Hopefully this isn't confusing, and if it is here is a simple example:
Take for example I have 5 cells in my uitableview. each of the 5 cells has an uiimageview since my cells are customely made and has its own class. How would I rotate all 5 uiimageviews?
Thanks for all your help,
kevin
In your timer callback function you want to do something like this.
NSArray* cellArray = [yourTableView visibleCells];
for (UITableViewCell* cell in cellArray)
{
// do your cell by cell rotation here
}
To do this when you create your cell for an infinite animation you can use the following code. Keep in mind that if you are caching cells then you only need to do this on cell creation, not on the cached cells.
[UIView beginAnimations:#"looping animation" context:nil];
[UIView setAnimationRepeatCount:0]; // 0 is infinite
[UIView setAnimationDuration:3];
// other animation options here if you'd like, and the duration can be anything, not just 3.
[UIView animateWithDuration:3 delay:0 options:UIViewAnimationOptionRepeat animations: ^{
// do your rotation stuff on your image, in this block, for the cell you will be returning.
} completion:nil];
[UIView commitAnimations];
Using a timer for animation isn't the best approach.
If you insist, I suggest you simply enumerate the visible cells (using the visibleCells tableview method) in the table view with each tick, and perform you rotation action on each cell.
How about some methods of UIView which controls the animation flow? You can repeat the animation of rotating.