iOS how-to: mask and shadow views
Two techniques that iOS developers use to make visually appealing app are masks and shadows; for example, masking an image to have round corners, or adding a drop shadow to an image to have depth. Implementing these techniques separately is trivial, implementing these techniques together is tricky.
To both mask and shadow any view, let’s use an image as an example, you:
- create a new layer whose layer has a shadow.
- mask the image’s layer.
- add the image’s layer as a sublayer of the shadow layer.
- add the shadow layer as a sublayer of the view that you want to show the image in.
I’ve created a project on GitHub, and wrote my commits in such a way as to see the stages of building our final result.
We start with an image as a subview of our view with no changes other than centering it.
//
// TJViewController.m
// MaskAndShadow
//
// Created by Travis Jeffery on 2012-08-06.
// Copyright (c) 2012 Travis Jeffery. All rights reserved.
//
#import "TJViewController.h"
@interface TJViewController ()
@end
@implementation TJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// white bg to see the shadow easier
self.view.backgroundColor = [UIColor whiteColor];
// the image we're going to mask and shadow
UIImageView* image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sj.jpeg"]];
image.center = self.view.center;
[self.view addSubview:image];
}
@end
Then we turn our image into a circle by masking its corners.
//
// TJViewController.m
// MaskAndShadow
//
// Created by Travis Jeffery on 2012-08-06.
// Copyright (c) 2012 Travis Jeffery. All rights reserved.
//
#import "TJViewController.h"
@interface TJViewController ()
@end
@implementation TJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// white bg to see the shadow easier
self.view.backgroundColor = [UIColor whiteColor];
// the image we're going to mask and shadow
UIImageView* image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sj.jpeg"]];
image.center = self.view.center;
// use the image's layer to mask the image into a circle
image.layer.cornerRadius = roundf(image.frame.size.width/2.0);
image.layer.masksToBounds = YES;
[self.view addSubview:image];
}
@end
If we added the shadow to the image’s layer, the mask on the image’s layer would cut off the shadow. Instead, we add the shadow to the parent layer of the image. And then we add that shadow layer to the view controller’s view layer.
//
// TJViewController.m
// MaskAndShadow
//
// Created by Travis Jeffery on 2012-08-06.
// Copyright (c) 2012 Travis Jeffery. All rights reserved.
//
#import "TJViewController.h"
#import <QuartzCore/QuartzCore.h>
@interface TJViewController ()
@end
@implementation TJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// white bg to see the shadow easier
self.view.backgroundColor = [UIColor whiteColor];
// the image we're going to mask and shadow
UIImageView* image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sj.jpeg"]];
image.center = self.view.center;
// make new layer to contain shadow and masked image
CALayer* containerLayer = [CALayer layer];
containerLayer.shadowColor = [UIColor blackColor].CGColor;
containerLayer.shadowRadius = 10.f;
containerLayer.shadowOffset = CGSizeMake(0.f, 5.f);
containerLayer.shadowOpacity = 1.f;
// use the image's layer to mask the image into a circle
image.layer.cornerRadius = roundf(image.frame.size.width/2.0);
image.layer.masksToBounds = YES;
// add masked image layer into container layer so that it's shadowed
[containerLayer addSublayer:image.layer];
// add container including masked image and shadow into view
[self.view.layer addSublayer:containerLayer];
}
@end