UIView: How to Make Shiny Backgrounds and Other Reusable Styles

by Chadwick Wood
October 1st, 2010

When I first started making iPhone apps, I wrote a lot of repetitive code to style interface elements. Certainly, getting comfortable with Interface Builder eases that pain to some degree, but IB won't allow you to take advantage of a lot of available built-in styling features for your interface elements, such as curved corners, drop shadows, and stroked borders. Additionally, you can create beautiful gradient backgrounds in code pretty easily, but the code is somewhat verbose, so it really pays off to find good ways of re-using that kind of code. Also, using a programmatic approach to your app styling can eliminate the production time associated with image-based styles (e.g. custom background images). A lot of common effects used in UIs can be realized without any images whatsoever.

Today, I want to show you a couple of methods that encapsulate code-based styling for your UIViews and their descendants. These methods can be used either in a subclass of UIView, or a Category on UIView. My recommendation is to go the Category route, so that you can use the methods on any UIView or subclass (e.g. UIImageView). However, if you end up creating styles that need their own instance variables, then you'll need to write a subclass. If you need more information what a Category is or how to create one, check the Apple documentation.

Curved Corners, Stroked Borders, and Drop Shadows

Here's a method to encapsulate some style settings that use the CALayer instance (the layer property) inside of a UIView. Let's say we have an app in which we repeatedly use the style of a UIView with 4-pixel-radius curved corners, a 1-pixel light gray border, and a mild drop shadow. We can write a method that applies those styles to a UIView (make sure you import QuartzCore so that this method will compile):

#import 

...

- (void)applyDefaultStyle {
    // curve the corners
    self.layer.cornerRadius = 4;

    // apply the border
    self.layer.borderWidth = 1.0;
    self.layer.borderColor = [[UIColor lightGrayColor] CGColor];

    // add the drop shadow
    self.layer.shadowColor = [[UIColor blackColor] CGColor];
    self.layer.shadowOffset = CGSizeMake(2.0, 2.0);
    self.layer.shadowOpacity = 0.25;
}

Doing this, we have a central place in our app that this style is defined. If, later in development/design iterations, we realize that all of those elements should have a dark gray border, we just have to make that change in one place.

Adding a Shiny Gradient Background

Next, let's create a method to apply a shiny-looking gradient to the background of any UIView. As a bonus, we'll set up the method such that any single color can be passed in, and the gradient will be drawn in that color. Note, the method I write here assumes that the color passed in is a UIColor in RGBA mode (not grayscale).

- (void)applyShinyBackgroundWithColor:(UIColor *)color {

    // create a CAGradientLayer to draw the gradient on
    CAGradientLayer *layer = [CAGradientLayer layer];

    // get the RGB components of the color
    const CGFloat *cs = CGColorGetComponents(color.CGColor);

    // create the colors for our gradient based on the color passed in
    layer.colors = [NSArray arrayWithObjects:
                                    (id)[color CGColor],
                                    (id)[[UIColor colorWithRed:0.98f*cs[0]
                                                         green:0.98f*cs[1]
                                                          blue:0.98f*cs[2]
                                                         alpha:1] CGColor],
                                    (id)[[UIColor colorWithRed:0.95f*cs[0]
                                                         green:0.95f*cs[1]
                                                          blue:0.95f*cs[2]
                                                         alpha:1] CGColor],
                                    (id)[[UIColor colorWithRed:0.93f*cs[0]
                                                         green:0.93f*cs[1]
                                                          blue:0.93f*cs[2]
                                                         alpha:1] CGColor],
                                    nil];

    // create the color stops for our gradient
    layer.locations = [NSArray arrayWithObjects:
                        [NSNumber numberWithFloat:0.0f],
                        [NSNumber numberWithFloat:0.49f],
                        [NSNumber numberWithFloat:0.51f],
                        [NSNumber numberWithFloat:1.0f],
                        nil];

    layer.frame = self.bounds;
    [self.layer insertSublayer:layer atIndex:0];
}

This method creates a CAGradientLayer, draws our styled gradient onto it, and then inserts that layer into the UIView at the appropriate location.

So, with these two methods alone, you can create a nice-looking, stylized UIView, without using any decorative images. If you have any questions on how some of this stuff works, let me know in the Comments.