I recently began writing a short example to learn more about the iOS 5 Appearance API and customizing UINavigationBar objects. The goal was to add a custom background, title and text to the navbar. Once I had this working, to keep a consist look across my application, I began tweaking the buttons on the navbar using the same Appearance API. As I got further into the customization of the buttons, I ran into a method withinUIImage that was introduced in iOS 5, resizableImageWithCapInsets. I found myself getting side-tracked from the original idea of navbar look and feel, to understanding how cap insets work. This post delves into what I learned.

Cap Insets with UIButton As the documentation describes, you use resizableImageWithCapInsets to add cap insets to an image, when the image is resized or scaled, cap areas are not affected. The best way to understand this is through an example. Let’s assume I want all the buttons on my UI to have a similar look, a gradient with a white border. Below is the image used for the examples in this post (the button is shown on a gray backdrop so you can scxxx[ ]]]ee the white border):

2013-10-10-1

Depending on the context of where the button appears, its size may vary. The code to create a button with the image and the corresponding output follow:

1
2
3
4
5
6
7
8
9
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(80, 130, 160, 44)];  
[button setTitle:@"Test Button" forState:UIControlStateNormal]; 

// Image with without cap insets
UIImage *buttonImage = [UIImage imageNamed:@"blueButton"];   

[button addTarget:self action:@selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[[self view] addSubview:button];

2013-10-10-2

As you can see, the button is stretched in all directions. Let’s change the code to include cap insets, however, before we do that, let’s look at the signature of the cap insets method:

1
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets

Looking on step further, UIEdgeInserts is defined as:

1
2
3
typedef struct {  
   CGFloat top, left, bottom, right;
} UIEdgeInsets;

UIEdgeInsets is structure that specifies float values for each cap inset: top, left, bottom and right areas of an image. To apply this to the image for the button, here is all we need to do:

1
2
// Image with cap insets
UIImage *buttonImage = [[UIImage imageNamed:@"blueButton"]     resizableImageWithCapInsets:UIEdgeInsetsMake(0, 16, 0, 16)];

This requests that the left and right 16 pixels of the original image are not scaled or resized when stretching the image to accomodate the button size frame defined above. The end results is as shown below:

2013-10-10-3

Cap Insets with UIBarButtonItem We can use the same image for a button on a navbar (I’ll show the specifics in the next post on customizing the navbar). Without specifying the cap insets, the button looks as follows:

2013-10-10-4

The code below specifies an image where 12 pixels on the top, left, bottom and right be preserved when stretching/resizing the button:

1
UIImage *backButton = [[UIImage imageNamed:@"blueButton"]     resizableImageWithCapInsets:UIEdgeInsetsMake(12, 12, 12, 12)];

The output nows looks as follows:

2013-10-10-5