Skinning UISegmentedControl

Note: I wrote this tutorial in May 2010 for use with iOS v3.2. It may or may not work with the most recent version of iOS.

Segmented Control buttons are really useful. However, making them look like anything other than the three built-in styles is a little bit of a pain. Unlike regular buttons, you can't really just set an image to them and have it come out nice (as bits of the default look are going to poke out). So, there's a simple workaround:

Step 1 - Create a Segmented Button in Interface Builder

This should be pretty self explanatory. Open your XIB file in Interface Builder and drag your segmented control from the library onto your view design. Don't worry about anything else regarding this button for now.

Step 2 - Hook it Up!

The next thing you want to do is set up your code to accommodate the segmented control. You'll need an IBOutlet as well as an IBAction. You'll want something like this:

@interface SegmentedDemoViewController : UIViewController {
    IBOutlet UISegmentedControl *segControl;
}

- (IBAction)segSwitch:(UISegmentedControl* )sender;

@end

Save that, then go back to Interface Builder. Ctrl+drag from File's Owner to the button and select segControl. Then, ctrl+drag the opposite direction and select segSwitch. That should be all you need to hook up here.

Step 3 - Design Your New Buttons

This is the most interesting part of skinning buttons--actually designing your new buttons. This part is entirely up to you. However, if you want a few tips, I'll explain the way I went about doing this.

First, I made sure that the existing segmented button was the size I wanted my final buttons to be. Then, I took a screenshot, and cropped it down to just the button.

Then, in Photoshop (or Gimp or whatever you want to use), I drew my new buttons on a new layer over top of the old buttons. Then, I deleted the layer with the original buttons, leaving just the one I created. In this particular image, the minus is selected whereas the plus isn't. This isn't very obvious by the example image, but nobody said tutorial images had to be pretty. I expect you to make it a lot more intuitive in your program!

Now I make the opposite--plus is selected and minus isn't.

These are the only two images I need for a regular 2-part segmented button. You will need more for more buttons, or more if you allow for neither or both buttons to be selected. Basically you will almost always want an image for every potential state of the button in order to make it user friendly. When your buttons are done, then you can move on to...

Step 4 - Setting Up Your Button Skin in Interface Builder

This is where the magic happens. First, you need to add another IBOutlet to your code. This will be a UIImageView that represents the buttons you designed. A line like this will do:

IBOutlet UIImageView *segImage;

Before adding your UIImageView in Interface Builder, you'll want to add your button images to your Resources folder. Right click the Resources folder, select "Add->Existing Files...", then select your images. For this tutorial I named them minusSelected.png and plusSelected.png. I'd recommend similar names that tell you exactly what button state that image represents.

Save, then open up your XIB again. Drag an Image View onto your view, ctrl+drag from File's Owner to the Image View and select segImage. I'd recommend going ahead and resizing your Image View to the size of the buttons you created. Under the Image View's attributes, select the image file you want to be the default when starting the program. For me, this will be minusSelected.png. If you need transparency, untick the box under that that says "Opaque".

Jeepers, that's an ugly button! I hope that inspires you to design something nice. The next step is to select the Segmented Button, and look under the attributes at the alpha value. It's above the background color. Set the alpha value to 0.10--this should be enough to make it nearly invisible. If you can still see it clearly (perhaps depending on your background color), you can try lower values, but I've noticed that if it goes too low the button no longer functions. Also, remember to remove the default text labels from the button (First, Second, etc.). If you need text overlays on your buttons, you can make regular text Labels and switch them in your code later.

Now, all you have to do is drag your image on top of the segmented button. Looking good!

Step 5 - Write Some Code

All that's left is to add your segmented button to your code. This means we'll be writing the segSwitch function. The function basically just consists of a switch/case, which you should be familiar with even if you haven't used one in a long time. This is where you'll also be writing your functionality for the segmented button. The example code below just shows you how the images are being used to show the states of the segmented button--however, you'll more than likely want to add more code to this, or else your button doesn't actually DO anything.

- (IBAction)segSwitch:(UISegmentedControl* )sender
{
    switch (segControl.selectedSegmentIndex)
    {
        case 0:
            /*The first segmented object is selected.*/
            segImage.image = [UIImage imageNamed:@"minusSelected.png"];
            break;
        case 1:
            /*The second segmented object is selected.*/
            segImage.image = [UIImage imageNamed:@"plusSelected.png"];
            break;
        default:
            /*Default segmented object is selected.*/
            segImage.image = [UIImage imageNamed:@"minusSelected.png"];
            break;
    }
}

Case 0 represents the first segment of the button, case 1 represents the second, etc. All you're doing here is changing the image displayed in segImage to the image that represents the state of the case your button is currently giving you. So, if the case is 0, then the first segment is selected. Therefore, you need to change the image of segImage to minusSelected, since minus is your first segment. The default is there in case something goes wrong and you receive something other than the cases you have set up, and it's best to have it just default back to what state the segmented button is in when you start the program. Remember, if you have more than two segments you'll need more cases!

Done!

You've now created a working, custom-skinned UISegmentedControl! You're no longer limited to the three options Apple gives you. Actually, let's face it, it's more like two and a half options since two of them are almost identical. This example was fairly specific, and I'm sure you could do a lot more things with this same idea. I've done similar things with invisible buttons to cause images to change when touched, just play around with the idea and enjoy. If you can't get this working, I've also uploaded the XCode project I used for this tutorial:

Download SegmentedDemo Project