19

I have a label which pops up displaying points in my application. I am using the following code to make the label get larger in scale, then smaller. I would also like to animate the color changing from purple to green. Can someone point me to a resource in achieving this?

mLabel.textColor = [UIColor purpleColor];

 [UIView beginAnimations:nil context:NULL];
 [UIView setAnimationDuration:1.0];
 [UIView setAnimationDelegate:self];
 mLabel.transform = CGAffineTransformMakeScale(1.5,1.5);
 [UIView setAnimationRepeatCount:1];
 mLabel.transform = CGAffineTransformMakeScale(0.5,0.5);
 mLabel.textColor = [UIColor greenColor];
 [UIView commitAnimations];
SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87
Oh Danny Boy
  • 4,857
  • 8
  • 56
  • 88

7 Answers7

67

You can use iOS 4.0's view transition method to do this:

[UIView transitionWithView:statusLabel duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
    [statusLabel setTextColor:[UIColor whiteColor]];
    [statusLabel setShadowColor:[UIColor blackColor]];
} completion:nil];
CIFilter
  • 8,647
  • 4
  • 46
  • 66
  • Wow! This is excellent! Thanks for sharing this! Sorry for the exclamation marks, but I was about to create a subclass of CATextLayer. – RileyE Oct 05 '12 at 21:32
  • This is an excellent tip. The accepted answer is probably more technically correct, but this method achieves very much the same effect. Many thanks. – LeffelMania Jan 08 '13 at 06:51
  • Correct. Using a `CATextLayer` is the more correct answer as it will interpolate the color values in between the from and to colors. However, this is handy when a basic crossfade transition from one color to another is sufficient. – CIFilter Apr 04 '13 at 20:24
  • Great! This saved me from messing around with subclassing UILabel that uses CATextLayer – sensslen Dec 30 '13 at 09:33
  • 1
    NICE! a minor problem I found: if you are otherwise animating the view (e.g. moving it), the dissolve can have some unexpected results; in my case, the 'old' version of the view stops in mid-animation and starts to dissolve all by its lonesome – toblerpwn Jan 04 '14 at 22:38
  • That's pretty typical. If you're going to apply any type of `CATransition` (which is what this does), then you have to be careful not to also animate the geometry of the view. Instead, place the view to fade inside a container view (or layer) and animate that view's geometry instead. – CIFilter May 12 '14 at 20:50
  • I should also mention that it's possible that `CATextLayer` does more sophisticated color interpolation. I'm not positive, but I imagine that it could easily interpolate between HSV representations instead of RGB representations, which produces inferior perceptual interpolation when compared to HSV. `CATransition` is just going to crossfade the two rendered bitmaps, which would just be simple RGB interpolation in the case of color values. – CIFilter Mar 04 '15 at 02:20
27

Unfortunately, the color doesn't animate with UIView animations. The answers to this question give some good workarounds without using Core Animation.

If you don't mind using a CATextLayer instead of a UILabel, then the color (and the scaling in your example) can be animated like this:

#import <QuartzCore/QuartzCore.h>
//Also need to add QuartzCore framework to project (as well as the import).
//
-(void)animateTextLayer {

CGFloat animationDuration = 5;

CATextLayer *textLayer = [CATextLayer layer];
[textLayer setString:@"Hello World"];
[textLayer setForegroundColor:[UIColor purpleColor].CGColor];
[textLayer setFontSize:30];
[textLayer setFrame:CGRectMake(20, 200, 300, 40)];
[[self.view layer] addSublayer:textLayer];

CABasicAnimation *colorAnimation = [CABasicAnimation 
                                     animationWithKeyPath:@"foregroundColor"];
colorAnimation.duration = animationDuration;
colorAnimation.fillMode = kCAFillModeForwards;
colorAnimation.removedOnCompletion = NO;
colorAnimation.fromValue = (id)[UIColor purpleColor].CGColor;
colorAnimation.toValue = (id)[UIColor greenColor].CGColor;
colorAnimation.timingFunction = [CAMediaTimingFunction 
                                 functionWithName:kCAMediaTimingFunctionLinear];

CAKeyframeAnimation *scaleAnimation = [CAKeyframeAnimation 
                                        animationWithKeyPath:@"transform"];
NSArray *scaleValues = [NSArray arrayWithObjects:
    [NSValue valueWithCATransform3D:CATransform3DScale(textLayer.transform, 1, 1, 1)],
    [NSValue valueWithCATransform3D:CATransform3DScale(textLayer.transform, 1.5, 1.5, 1)],
    [NSValue valueWithCATransform3D:CATransform3DScale(textLayer.transform, 0.5, 0.5, 1)], nil];
[scaleAnimation setValues:scaleValues]; 
scaleAnimation.fillMode = kCAFillModeForwards;
scaleAnimation.removedOnCompletion = NO;

CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.duration = animationDuration;
animationGroup.timingFunction = [CAMediaTimingFunction 
                                functionWithName:kCAMediaTimingFunctionLinear];
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.removedOnCompletion = NO;
animationGroup.animations = 
        [NSArray arrayWithObjects:colorAnimation, scaleAnimation, nil];

[textLayer addAnimation:animationGroup forKey:@"animateColorAndScale"];
}
Community
  • 1
  • 1
  • if only there would be a way to set a vertical alignment in CATextLayer – bioffe Nov 19 '10 at 22:52
  • 4
    Here's a _much_ better workaround using just the original UILabel itself: http://stackoverflow.com/questions/6442774/is-uilabels-backgroundcolor-not-animatable/6442868#6442868 –  Mar 13 '12 at 15:29
  • 2
    @AnnaKarenina the link you pointed is to animate background colour. – xhan Jul 16 '12 at 11:53
  • It's still pretty useful link, for people who DO were trying to animate backgroundColor (like I was :) – Vinzzz Feb 26 '14 at 15:39
6

The reason that textColor is not animatable is that UILabel uses a regular CALayer instead of a CATextLayer.

To make textColor animatable (as well as text, font, etc.) we can subclass UILabel and make it use a CATextLayer.

This is quite a lot of work, but luckily I already did it :-)

You can find a complete explanation + a drop-in open source replacement for UILabel in this article

adamsiton
  • 3,642
  • 32
  • 34
1

If you need to use IB colors that are specified for highlighted or selected states and want to animate the color change with fade out effect you can use next code:

Swift:

@IBAction func buttonAction(sender: AnyObject) {

    // Set selected to leave same color as for highlighted
    // (default=black, highlighted=red, selected=red)
    self.openAllButton.selected = true

    // Delay before the color change animation 
    let delayInSeconds = 0.1;
    let delay = delayInSeconds * Double(NSEC_PER_SEC)
    let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay));
    dispatch_after(popTime, dispatch_get_main_queue(), {
        // Animate color change
        UIView.transitionWithView(self.openAllButton, duration: 1.0, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: { () -> Void in
            self.openAllButton.selected = false          // selected->default
            }) { (v:Bool) -> Void in
        }
    });

}

Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
1

This line of code works for me. Make sure to set the Options to Cross Dissolve Swift:

static func animationButtonTextColor(button : UIButton, toColor : UIColor, duration : NSTimeInterval) {
    UIView.transitionWithView(button, duration: duration, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
      button.setTitleColor(toColor, forState: .Normal)
    }, completion: nil)
  }
0

Try This:

[UIView animateWithDuration:0.5 animations:^{

    label.alpha=0.3;


}completion:^(BOOL finished)
 {
    label.backgroundcolor=[uicolor purplecolor]; 


     [UIView animateWithDuration:0.5 animations:^{

         label.alpha=1.0;

     }completion:^(BOOL finished)
      {

      }];

 }];
byJeevan
  • 3,728
  • 3
  • 37
  • 60
bharathi kumar
  • 210
  • 2
  • 8
0

Add this before your call to commitAnimations:

[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:mLabel cache:YES];
rpetrich
  • 32,196
  • 6
  • 66
  • 89