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)];
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)]
You can see the full source in the custom segmented controls source: https://github.com/boctor/idev-recipes/blob/master/CustomSegmentedControls/Classes/CustomSegmentedControlsViewController.m
I have implemented this and it works fine with any OS, which is higher than OS4.0. This is because the UIGraphicsBeginImageContextWithOptions method is introduced in OS4.0. Is there any way to get this working in anything less than OS4.0? Help would be much appreciated.
Julian, here is how to check for iOS 4 and use the older UIGraphicsBeginImageContext if necessary:
Hi Peter,
I have done this, but, the old method uses a default (unchangeable) scale factor of 1.0, when to get this working you need to use 0.0. Thus the tab center is separated from the tab end by 1 pixel space.
What do you think?
Hi Peter, thank you for it.
I need to do something like this: http://img94.imageshack.us/img94/4407/segmentedbutton.png
How I do it?