Question

If I want to animate UITableViewCell so it would bounce from left to right a few times, How can I do that? I'm trying that:

var bounds = activeCell.Bounds;
var originalLocation = bounds.Location;
var loc = originalLocation;

UIView.Animate(0.2,()=>{
   loc.X = originalLocation.X + 20;
   activeCell.Bounds = new RectangleF (loc, bounds.Size);   
   loc.X = originalLocation.X - 20;
   activeCell.Bounds = new RectangleF (loc, bounds.Size);   
});

It animates only the last state (i.e. moves element to the left). I tried to put them in separated Animate blocks - it didn't help. Tried to use different UIAnimationOptions - the same.

Was it helpful?

Solution 4

Lack of documentation and good samples sometimes really makes even simple tasks so annoyingly challenging.

Here is the solution

Sure code isn't elegant, but it works. Hope it will someday help somebody else, so he or she wouldn't need to spend half a day on something stupidly simple like that

var activeCell = ((Element)sender).GetActiveCell();

var animation = 
 (CAKeyFrameAnimation)CAKeyFrameAnimation.FromKeyPath ("transform.translation.x");
animation.Duration = 0.3;

animation.TimingFunction = // small details matter :)
          CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut.ToString()); 

animation.Values = new NSObject[]{
                                   NSObject.FromObject (20), 
                                   NSObject.FromObject (-20),
                                   NSObject.FromObject (10),
                                   NSObject.FromObject (-10),
                                   NSObject.FromObject (15),
                                   NSObject.FromObject (-15),
                                 };

activeCell.Layer.AddAnimation (animation,"bounce");

OTHER TIPS

Here is a nice article explaining how to make it bounce.

http://khanlou.com/2012/01/cakeyframeanimation-make-it-bounce/

Moreover, there is an explanation the formula used to compute the bounce path. For my personal use, I've taken the absolute value of the computation to simulate a rebound on ground.

- (void) displayNoCommentWithAnimation{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position.y"];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.duration = 2;

int steps = 120;
NSMutableArray *values = [NSMutableArray arrayWithCapacity:steps];
double value = 0;
float e = 2.71;
for (int t = 0; t < steps; t++) {
    value = 210 - abs(105 * pow(e, -0.025*t) * cos(0.12*t));
    [values addObject:[NSNumber numberWithFloat:value]];
}
animation.values = values;

animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.delegate = self;
[viewThatNeedToBounce.layer addAnimation:animation forKey:nil];
}


- (void) animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
CAKeyframeAnimation *keyframeAnimation = (CAKeyframeAnimation*)animation;
[viewThatNeedToBounce.layer setValue:[NSNumber numberWithInt:210] forKeyPath:keyframeAnimation.keyPath];
[viewThatNeedToBounce.layer removeAllAnimations];
}

The problem with your approach is that UIView.Animate will record the changes that you make to your view, but only the final state for them.

If you change the Bounds property one hundred times in your animate block, only the last one is the one that will matter from the perspective of the animation framework.

CoreAnimation has a couple of quirks that are explained in the WWDC 2010 and WWDC2011 videos. They have great material and they explain a few of the tricks that are not very obvious.

That being said, animating cells in a UITableView is a complicated matter because you are really poking at a UITableView internals, so expect various strange side effects. You could lift the code from TweetStation that does that animation and deals with various corner cases. But even TweetStation and the Twitter for iOS app do not manage to be perfect, because you are animating things behind the back of a UIView that is constantly updating and making changes to very same properties you are animating.

From the top of my head, the easiest approach would be to put the animation code into a method and call that recursive as often as you want. Code untested, but it should work or at least give you an idea.

// Repeat 10 times, move 20 right and the left and right etc.
FancyAnim(activeCell, activeCell.Bounds.Location, 10, 20);

private void FancyAnim(UITableViewCell activeCell, PointF originalLocation, int repeat, float offset)
{
var bounds = activeCell.Bounds;
var loc = originalLocation;

UIView.Animate(0.2,
delegate
{
  // Called when animation starts.
   loc.X = originalLocation.X + offset;
   activeCell.Bounds = new RectangleF (loc, bounds.Size);   
},
delegate
{
  // Called when animation ends.
 repeat--;
// Call the animation method again but invert the movement.
// If you don't do this too often, you should not run out of memory because of a stack overflow. 
if(repeat >= 0)
{
  FancyAnim(activeCell, originalLocation, repeat, -offset);
}
});

You can however also use a path animation. You would define a path "20 units right, back to center, 20 units left, back to center" and repeat that animation as often as you like. This requires you to deal with CAKeyFrameAnimation and will be slightly more code. This site can get you jump started: http://www.bdunagan.com/2009/04/26/core-animation-on-the-iphone/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top