Fade Transition – Fade Images In and Out

Although the iPhone includes a number of effects designed for transitioning between views, sometimes a simple fading effect of one image to another, within the same view, is all you need.

For example, in a recent application during the application startup, I wanted the splash image to fade away, and another image of the primary user interface, to become front and center.

The effect I was after looks similar to the video shown below:

Interface Definition
@interface SomeClass : UIViewController
{
  UIImageView *layer1;		
  UIImageView *layer2;
  NSTimer      *timer;
  ...
}
Implementation

Here is the setup, which includes two images, one that is visible that we will fade out, and one this is transparent that will become visible.

- (void)fade
{
  // The lower image, that will be visible after the fading effect
  layer1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image2.png"]];
  // Start with this layer fully transparent
  layer1.alpha = 0;
  [window addSubview:layer1];
 
  // The upper layer will transition from alpha 1 to 0
  layer2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image1.png"]];
  [window addSubview:layer2];
 
  // Call the timer every one hundreth of a second
  timer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(fadeTimerEvent) userInfo:nil repeats:YES];
}

The next block of code handles the timer event, where we tweak the alpha values of the images to provide the fading effects.

 
// Rate of transition for alpha values
#define FADE_IN_RATE		1.0/1000.0
#define FADE_OUT_RATE		2.0/1000.0
 
- (void)fadeTimerEvent
{
  if (layer1.alpha >= 1)
  {
    // At this point, layer1 is now visible  
    [timer invalidate];
    timer = nil;      
  }
  else
  { 
    // Fade lower layer in (increase alpha)
    layer1.alpha += FADE_IN_RATE;
 
    // Fade upper layer out (decrease alpha)
    layer2.alpha -= FADE_OUT_RATE;
  }
}

You can tinker with the fade in and fade out rates depending on the effect you are after.

I tossed this together when I needed a quick solution, and honestly, it seems like a rather brute force way to get the job done. If you have a more elegant solution, please post a comment.

  1. viewHolder is a UIView containing both subview-s.

    Not tried but should do the trick.

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:5];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationTransition:UIViewAnimationTransitionNone forView:viewHolder cache:YES];
    layer1.alpha = 1;
    layer2.alpha = 0;
    [UIView commitAnimations];

  2. Core Animation simplifies this a lot. Try this (untested):

    -(void)fade
    {
    layer1.alpha = 0;
    [UIView beginAnimations:@”FadeIn” context:nil];
    [UIView setAnimationDuration:1];
    layer1.alpha = 1;
    [UIView commitAnimations];

    [UIView beginAnimations:@”FadeOut” context:nil];
    [UIView setAnimationDuration:0.5f];
    layer2.alpha = 0;
    [UIView commitAnimations];
    }

    This should accomplish the same thing.

  3. The Andy approach doesn’t guarantee that the second animation will end before the first one, because in this way are fired two thread and you have no guarantee how the thread manager will handle them, they are asynchronous.

  4. The transition used in all of the AppStore applications I have written for a customer only fade one image, while the other image is static with alpha = 1.0 right behind the fading image.

    Basically like Andrea’s but one less animation

    – (void)fade
    {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:5];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
    [UIView setAnimationsEnabled:YES];
    [UIView setAnimationDidStopSelector:@selector(animationEnded)];
    [UIView setAnimationDelegate:self];
    layer2.alpha = 0;
    [UIView commitAnimations];
    }

    where layer2 has been added after layer1 so layer2 is on top and in this case [self animationEnded] gets called when done.

    Using a timer to do animations is very error prone, you can setup an CAAnimationGroup animation group with CAKeyframeAnimation key frame animations if you want to do anything special (like setting a delay time and length). The animations take care of setting up what you want to do in accelerated hardware. Timers just waste your time, pun intended, especially when trying to do complex things on slower iphones like the 2G and 3G phones.

    Try doing image rotation 30fps with timers, I have never seen the iphone simulator run so slow. Then use [CAKeyframeAnimation animationWithKeyPath:@”transform.rotation”] and it is all in hardware.
    Let CoreAnimation work for you, it is pretty powerful.

  5. Agree with the others, you should use Core Animation rather than timers – core animation is designed for this and the code is much simpler (and probably more performant).

    • Dustin,

      Are you referring to fading into a movie after the splash (Default.png)? I imagine you could place a MoviePlayer on a view controller and overlay that with an image (for example Default.png so it is the same as the splash image). Start the movie and then start the fade effect to dissolve the top image leaving the video showing.

Comments are closed.