Fun with gradient masks and the iOS 7 status bar

Prior to iOS 7 designers and developers didn’t really think much of the status bar. It existed outside of our application’s frame and simply occupied 22 pts of screen space. Now that’s all changed. The new status bar is in your application, and we as app makers have to come up with new and interesting ways to work with it. If you’ve ever made an app with scrolling content then at some point you’ve probably had to deal with this:

This isn’t going to work, the status bar text is clashing with our content. There are a lot of different ways to handle this and I’m going to show you one really cool way using an alpha gradient mask and CAGradientLayer. Here is the result:

Now something like this could be done in Photoshop. You could create the top part of the background as a separate image, feather the bottom and overlay it. However I’m going to show you how to do this programmatically. I will assume that you already know how to set up a UICollectionView, if not there is a link to the full source covered in this article here.

Let’s get started. Create a new collection view and set its frame to take up the entire screen. Then setup a new UIImageView with your background image and set it as the backgroundView of the collection view.

collectionView = [[UICollectionView alloc] initWithFrame:[[self view] bounds]];
// ... set delegate, datasource, etc.
[[self view] addSubview:collectionView];
[collectionView release];
 
// Set our "space" background image as the backgroundView.
UIImage *background = [UIImage imageNamed:@"space-background"];
UIImageView *backgroundView = [[UIImageView alloc] initWithImage:background];
[collectionView setBackgroundView:backgroundView];
[backgroundView release];

Since we are doing this programmatically we will only need the one image. The rest will be done in code.

The next step is to essentially take a screenshot of the background, but just the top portion. For this we can use CGImageCreateWithImageInRect. This function will create an image from an image, in the specified rectangle.

// First get a reference to our background image
UIImage *background = [(id)[collectionView backgroundView] image];
 
// This is the rectangle of the image that the status bar is covering
// we also need to adjust it for scale.
CGRect barRect = CGRectMake(0.0f, 0.0f, 320.0f, 28.0f);
barRect.size.width *= [background scale];
barRect.size.height *= [background scale];
 
// Create an image from the barRect area and convert it to a UIImage 
CGImageRef imageRef = CGImageCreateWithImageInRect([background CGImage], barRect);
UIImage *topImage = [UIImage imageWithCGImage:imageRef
                                        scale:[background scale]
                                  orientation:UIImageOrientationUp];
CGImageRelease(imageRef);

If you put a break point after the topImage line, you can mouse over to see what the image looks like in memory.

Lastly we need to create a view for this image to go on top of our collection view, and then apply an alpha gradient mask to it. For this we can use a CAGradientLayer with 2 colors: one transparent, one opaque – and by setting the startPoint and endPoint to cover the bottom half.

// Create a gradient layer that goes transparent -> opaque
CAGradientLayer *alphaGradientLayer = [CAGradientLayer layer];
NSArray *colors = [NSArray arrayWithObjects:
                   (id)[[UIColor colorWithWhite:0 alpha:0] CGColor],
                   (id)[[UIColor colorWithWhite:0 alpha:1] CGColor],
                   nil];
[alphaGradientLayer setColors:colors];
 
// Start the gradient at the bottom and go almost half way up.
[alphaGradientLayer setStartPoint:CGPointMake(0.0f, 1.0f)];
[alphaGradientLayer setEndPoint:CGPointMake(0.0f, 0.6f)];
 
// Create a image view for the topImage we created above and apply the mask
statusBarView = [[UIImageView alloc] initWithImage:topImage];
[alphaGradientLayer setFrame:[statusBarView bounds]];
[[statusBarView layer] setMask:alphaGradientLayer];
 
// Finally, add the masked image view on top of our collection view
[[self view] addSubview:statusBarView];
[statusBarView release]

That will do it. Now if you run your app you’ll see your content fade nicely as it slides underneath the status bar, and since we did it in code you could easily apply this to any or all of the views in your application.

Full source can be found on GitHub.