Chomper Stomping jQuery/JavaScript/CSS 3/HTML 5, Java/PHP/Python/ActionScript, Git, Chrome/Firefox Extensions, Wordpress/Game/iPhone App Development and other random techie tidbits I've collected

10Jun/098

Creating Dynamically Re-sizable Buttons for iPhone Apps

Creating buttons that resize/stretch themselves automatically for your iPhone Applications is pretty easy.

Buttons are created as .png files with three parts: Left end-cap, middle (the stretch-able part), Right end-cap. Basically, you create a little tiny .png file with the left and right end caps (or top and bottom) and a little bity middle part that the iPhone will automatically re-size to fit any width or height you make the button.

I'll walk you through the process step by step and show you how to assign the image to your button.

If you are wondering how to get your Round Rect Buttons to look like the ones in the official iPhone apps (like the ones apple makes), this tutorial will show you how. Instead of creating your own button image, just use the ones from Apple, or download the zip file for this tutorial (the ones from Apple are in there too)

Creating the Stretchable iPhone App Button Image

To start with, you will need to actually create the button image. I used Fireworks to do this, but you could use Photoshop, Illustrator, Inkscape or Gimp if you are so inclined. I recommend Fireworks.

I wanted my button to mimic normal iPhone buttons, but also illustrate the concept of a "stretchy" button. So I made a square button with rotated square corners.

  1. Create a new image 30 x 50 (or there-abouts)
  2. step1

  3. Make sure to set the canvas color as "transparent"
  4. Mock-up your button shape
  5. step2

  6. Use the pen tool to trace it into a single shape
    step3

    I take the individual components from the last step, group them together, and lock them, and then trace around them with the pen tool. There's probably a better way, but this is the way I know. Use the guides to help you tweak it until you are satisfied

  7. Trace a smaller version of the button inside of the outline using the pen tool
  8. Fill in the inner button, and remove the line on it
  9. Fill in the outer button
  10. step4

    If the shape looks how you want it at this point, move on, otherwise, rinse and repeat...

  11. Color the button the way you want it
    step5

    The way I do this is to fill the outside shape with a dark grey (at the top) to light grey (at the bottom) linear gradiant with a 1px solid dark grey border (a little darker than the darkest part of the gradient). Then fill the inside shape with a custom linear gradient. This is the part that requires finesse. If you want it to look like an Apple button with the slick horizon line, start light, get progressively darker, and then in one pixel make a stark jump to the darkest shade of the color you are using, then get progressively light again.

    step5gradient

  12. Add a drop shadow to the inner shape
    step5dropshadow

    Click the inner shape. Click the "+" next to "Filters" in the Properties inspector. Select "Shadow and Glow > Drop Shadow". I've selected a distance of 2, Opacity of 100%, Softness of 1 and Angle of 267.

  13. Decide on the stretching points of your button

    Pick a point in the middle of the image where if that one pixel got stretched (repeated over and over again) to widen the button, it would look good (I chose 15px for the button I've been creating for this tutorial). Pick a point in the middle of the image where if that one pixel got stretched to lengthen the button, it would look good (I chose 27px for the button I've been creating for this tutorial). Make note of these two points as you will need to know them later.

  14. At this point you have completed the "up" state for the button.

  15. Save your file (I saved as "customButtonImageDefault.png")
  16. "Save As" and rename your file for the pressed or "down" state for the button (I saved as "customButtonImageDown.png")
  17. Choose a color for the downstate, and change each gradient point to a shade of that color.
    step6

    It makes it easier if you click the color wheel in the color chooser and use the slider on the right. Also, once you have chosen your base color after clicking the color wheel and adjusting the slider, click "Add to Custom Colors" so you don't have to re-find your base color again and again each time. You can just select it from the custom colors list at the bottom left of the color wheel menu and then use the slider to choose another shade of that color. Make sure not to move any of gradient points or they won't match up with the points you took note of earlier. Up states and Down states can have different stretch points if you want since you define each state's stretch points individually in the code, but it makes it easier if you just use the same points for up and down.

  18. Once you have edited all of the points. Open the images in fireworks and switch back and forth between them to compare how it's going to look when the button is pressed. When satisfied, save. Now you're ready to get to coding!
  19. custombuttonimagedefaultcustombuttonimagedown

Creating a Custom Re-sizable Button in an iPhone App

Ok, now that you've gotten your button created, it's time to implement it.

I expect you to already know how to create I phone apps, but if not, here are un-annotated pictures of me building the scaffolding to hold our custom buttons. Following the images are the explanation on how to use custom buttons.

Creating the Scaffolding to place the custom button in

Again, if you already have an app you are trying to use the custom button in, skip this step...

buttontutorial1buttontutorial2buttontutorial3buttontutorial4

Making the Custom Button in the iPhone App

  1. Open the interface builder and click on the button you would like to customize
    buttontutorial5
  2. Open the "Button Attributes" pane (Apple + 1)
  3. For "type" select "Custom"
    buttontutorial6

    At this point, if you didn't give the button a title, it will disappear (which is ok). If you need to find it and can't, in the main window (titled yourFileName.xib) there will be several objects. Expand the one that says "View" (or wherever you put your button) and you should see your button. Clicking on it there will highlight it in the layout window.

  4. Hold down "ctrl" and drag from the "File's Owner" object to the button.

    This can all be done from within the .xib window by switching to "list" view mode

  5. In the little context menu that pops up, select "customButton" (or whatever you called the button in your code)
    buttontutorialconnectbuttontooutlet
  6. Switch to the "size" window (Apple + 3)
  7. Set the size to at least 100 x 100
    buttontutorialbuttonsize

    This is just so we can see our image stretch. When you are doing this in a non-tutorial setting, you will probably not set this at all.

  8. Switch to the "Attributes" window (Apple + 1)
  9. In the "View" section (at the bottom), click on "Background"
    buttontutorialclickbackground
  10. In the "color" window that pops up, set "Opacity" to "0" (zero)
    buttontutorialopacity
  11. Switch back over to Xcode
  12. Locate your button files and drag and drop them into the "Resources" folder of your project
    buttontutorial7

    You will probably want to make sure and click the "Copy items into destination group's folder" button

  13. Click "Add" in the pop-up that appears
  14. Switch to your view controller file

    (the one that corresponds with the view you were just editing in the Interface Builder. The one that ends with ".m")

  15. Add the following code to the -(void)viewDidLoad{} method:

    buttontutorial8

    UIImage *buttonImageNormal = [UIImage imageNamed:@"customButtonImageDefault.png"];
    UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];

    UIImage *buttonImagePressed = [UIImage imageNamed:@"customButtonImageDown.png"];
    UIImage *stretchableButtonImagePressed = [buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];

    The first block of code defines the image for the normal (up) state of the button. The second block defines the image for the pressed (down) state of the button. The first line of each block loads the button image for that state into the app. The second line of each block you can set the stretch points of the button (you should have noted these earlier when you made the button). You can keep setting these to different things and viewing the result to refine until you like what you see. The third line assigns the now stretchable image to the actual button. If you have more than one button you want to assign the image to, just copy the third line and replace "customButton" at the beginning with the name of the next button you want to assign the image to:


    UIImage *buttonImagePressed = [UIImage imageNamed:@"customButtonImageDown.png"];
    UIImage *stretchableButtonImagePressed = [buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];
    [anotherCustomButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];
    [thirdCustomButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];

    In this way, you can assign the image to as many buttons as you want.

  16. Your viewDidLoad method should now look something like this:


    -(void)viewDidLoad {
    UIImage *buttonImageNormal = [UIImage imageNamed:@"customButtonImageDefault.png"];
    UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];

    UIImage *buttonImagePressed = [UIImage imageNamed:@"customButtonImageDown.png"];
    UIImage *stretchableButtonImagePressed = [buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:0];
    [customButton setBackgroundImage:stretchableButtonImagePressed forState:UIControlStatePressed];

    [super viewDidLoad];
    }

  17. Now hit Apple + R to compile, run and view the output!
    buttontutorialcomplete

A good amount of the information for this article came from
Beginning iPhone Development: Exploring the iPhone SDK. It's an excellent book. By far the best iPhone development book out there right now. It's really easy to read and understand. Each chapter is one or two example projects from start to finish, step by step, wonderfully explained. After buying this book I had my first iPhone App up and running within a week. The thing they don't talk about (that I did) was actually creating the button image, and dealing with the opacity. Again, all of the files for this tutorial can be downloaded from here. Feel free to leave any feedback/questions/whatever in the comments... Good luck!


Comments (8) Trackbacks (2)
  1. Yes, indeed.

    This book is really good, and your example is also very clar.

    Sadly my design skill were lost somewhere…. do you know where I can get images ready to apply to my stretchable buttons?

    Thanks.

    PS. Sorry about my English :S

  2. Sadly, I do not. Sorry.

    Your English was just fine ;)

  3. Nice article!
    Is there anyway to do this purely in Interface Builder?

    Thanks in advance

  4. Thanks! Not that I know of. If I find one I’ll make a post detailing it…

  5. Seems there is no UIControlStatePressed constant. Did you mean UIControlStateHighlighted?

  6. @dejo: Could be. This is using the old API so they may have changed it.

  7. This blog is bookmarked! I really love the stuff you have put here.

  8. Hi,
    Thanks!! This tuto is very good
    But I have question: How can I put my pictuer in center because when I use
    UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:13 topCapHeight:13];
    I found this problem…
    I wish to be clear and you understand me…
    I am waiting you answer………


Leave a comment