Full Source code: https://github.com/boctor/idev-recipes/blob/master/CustomSegmentedControls/Classes/CustomSegmentedControlsViewController.m

Problem:

We have an image that we need to crop. Specifically we have a stretchable image but we want to control which cap is visible on the image.

We ran into this when creating custom segmented controls. All we had was a stretchable image with rounded corner caps on both sides and a stretchable 1 pixel in the middle.

But the buttons for a segmented control have either only the left or right cap showing for the end buttons and for the middle button, neither cap is showing.

Solution:

We will use a graphics context to do the image cropping. If you haven’t used contexts before, Apple’s Quartz 2D Overview has a nice description.

To demonstrate, let’s use a stretchable image (‘image’ variable) with 14px caps (‘capWidth’ variable) and let’s generate images 150px wide (‘buttonWidth’ variable).

In all cases we create an image context that is 150px wide and as high as the image:

UIGraphicsBeginImageContextWithOptions(CGSizeMake(buttonWidth, image.size.height), NO, 0.0);

Remember that you can tell stretchable images to draw at any width and they will stretch to accomodate this width.

Left Cap Only

To draw only the left cap, we’ll tell the image to draw at (0,0), but we’ll expand the width enough so the right cap is drawn beyond the bounds of the context.

[image drawInRect:CGRectMake(0, 0, buttonWidth + capWidth, image.size.height)];

We then ask the context to draw itself into an image:

UIImage* resultImage = UIGraphicsGetImageFromCurrentImageContext();

Resulting in this image:

Right Cap Only

To draw only the right cap, we’ll tell the image to draw at (-14,0), and we’ll also expand the width enough so the left cap is drawn beyond the bounds of the context.

[image drawInRect:CGRectMake(0.0-capWidth, 0, buttonWidth + capWidth, image.size.height)];

Resulting in this image:

No Caps

To draw no caps, we’ll tell the image to draw at (-14,0), and we’ll also expand the width enough so that both caps are drawn beyond the bounds of the context.

[image drawInRect:CGRectMake(0.0-capWidth, 0, buttonWidth + (capWidth * 2), image.size.height)]

Resulting in this image:

You can see the full source in the custom segmented controls source: https://github.com/boctor/idev-recipes/blob/master/CustomSegmentedControls/Classes/CustomSegmentedControlsViewController.m

Advertisements