iOS Programming Recipe 20: Using CAGradientLayer In A Custom View

This recipe will demonstrate how to use CAGradientLayer to add gradients to a custom UIView.

Assumptions

  • You should have basic knowledge of UIView and Core Animation, specifically CALayer.
  • Basic knowledge of autolayout usage in interface builder.

Getting Started

Setting Up A Sample Application
  • Create a new Single View Application in Xcode named GradientViewDemo. Make sure to check Use Automatic Reference Counting and uncheck Use Storyboards. Our demo app will also be iPhone only to keep things simple, but go ahead make a universal app if you like (everything we will do is applicable on both iPhone and iPad),
  • Create a new UIView subclass named NSCBGradientView. We added the NSCB class prefix, because this may be a valuable component to reuse in future projects and the prefix will help avoid name clashing.
  • Next, we need to add QuartzCore to the target. Do so by selecting the project file in the source list on the left, then ensure the GradientViewDemo target has been selected, select the Build Phases tab from the tab bar at the top, expand the Link Binary with Libraries, and finally click the + button in the lower left corner. Search for QuartzCore, and then add it to the target.

  • Open ViewController.xib and drag a UIView into the root view. Now center the UIView and set it’s size to 200 x 200. You should have 4 constraints on the view. Promote them all to user constraints or create them if they are missing.

    • Height Equals: 200
    • Width Equals: 200
    • Align Center X to: SuperView
    • Align Center Y to: SuperView
  • Next we need to change the class of the UIView to NSCBGradientView. Open the Identity inspector and change class to NSCBGradientView.

  • Finally, create an IBOutlet for the gradientView in ViewController.h, you will also need to import NSCBGradientView here. Then open ViewController.xib and ctrl + drag from file’s owner to the gradientView and select gradientView from the HUD.

1
2
3
4
5
6
7
8
#import <UIKit/UIKit.h>
#import "NSCBGradientView.h"

@interface ViewController : UIViewController

@property (nonatomic, strong) IBOutlet NSCBGradientView *gradientView;

@end
Creating The Gradient View
  • Open NSCBGradientView.h and add an import QuartzCore at the top (this is where CAGradientLayer lives).
  • Next open NSCBGradientView.m we will override UIView’s layerClass class method and return CAGradientLayer instead of a plain old CALayer. This will tell this UIView to use a CAGradientLayer instead of CALayer.

1
2
3
4
5
6
#pragma mark - UIView

+ (Class)layerClass
{
    return [CAGradientLayer class];
}
  • Now let’s create a nice API for specifying the gradient colors. Open NSCBGradientView.h and add the following

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface NSCBGradientView : UIView

@property (nonatomic, readonly) CAGradientLayer *gradientLayer;

// An Array of UIColors for the gradient
@property (nonatomic, readwrite) NSArray *colors;

// Specifies that the gradient should be drawn horizontally
@property (nonatomic, getter = isHorizontal) BOOL horizontal;

@end
  • This is a very basic interface and by no means represents everything CAGradientLayer can do. I kept it simple in order to keep the sample code simple.
  • Now let’s implement that! Below is the implementation for NSCBGradientView.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#import "NSCBGradientView.h"

#define HORIZONTAL_START_POINT  CGPointMake(0, 0.5)
#define HORIZONTAL_END_POINT    CGPointMake(1, 0.5)
#define VERTICAL_START_POINT    CGPointMake(0.5, 0)
#define VERTICAL_END_POINT      CGPointMake(0.5, 1)

@interface NSCBGradientView ()

@end

@implementation NSCBGradientView

#pragma mark - UIView

+ (Class)layerClass
{
    return [CAGradientLayer class];
}

#pragma mark - Accessors

- (CAGradientLayer *)gradientLayer
{
    return (CAGradientLayer *)self.layer;
}

- (void)setColors:(NSArray *)colors
{
    NSMutableArray *cgColors = [NSMutableArray arrayWithCapacity:colors.count];
    for (UIColor *color in colors)
    {
        [cgColors addObject:(id)[color CGColor]];
    }

    self.gradientLayer.colors = cgColors;
}

- (NSArray *)colors
{
    NSMutableArray *uiColors = [NSMutableArray arrayWithCapacity:self.gradientLayer.colors.count];
    for (id color in self.gradientLayer.colors)
    {
        [uiColors addObject:[UIColor colorWithCGColor:(CGColorRef)color]];
    }

    return uiColors;
}

- (void)setHorizontal:(BOOL)horizontal
{
    self.gradientLayer.startPoint = horizontal ? HORIZONTAL_START_POINT : VERTICAL_START_POINT;
    self.gradientLayer.endPoint   = horizontal ? HORIZONTAL_END_POINT : VERTICAL_END_POINT;
}

- (BOOL)isHorizontal
{
    return (CGPointEqualToPoint(self.gradientLayer.startPoint, HORIZONTAL_START_POINT)) && (CGPointEqualToPoint(self.gradientLayer.endPoint, HORIZONTAL_END_POINT));
}

@end
  • The gradientLayer method is a convenience accessor that casts our backing layer accordingly.
  • setColors and colors translate between UIColor and CGColorRef. setColors sets an array of CGColorRef’s on the gradient layer, while colors translates the CGColorRef array to an array of UIColors.
  • Our API is very simple, a gradient by default is vertical, but also has a convenience method for switching to a horizontal gradient. This is done by setting the appropriate start end end points on the gradient layer.
  • For more advanced usage of the gradient layer, someone could subclass NSCBGradientView and add functionality, because we have exposed the gradient layer in the public interface.
Using The Gradient View
  • Open ViewController.m and add the following to ViewDidLoad

1
2
3
4
5
6
7
8
9
10
11
#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.gradientView.colors = @[[UIColor redColor], [UIColor orangeColor], [UIColor yellowColor]];
}

@end
  • Thats it, build and run, you should see something similar to the following (without the NSCookbook label, we didn’t cover adding that).
  • You can download the source code for this recipe on GitHub.

1

Speak Your Mind

*

css.php
Privacy Policy