Five Tips for Creating Stylish UIButtons

Five Tips for Creating Stylish UIButtons

Tutorial Details
  • Technology: iOS 5 SDK
  • Difficulty: Beginner
  • Completion Time: 15 - 30 Minutes

Sometimes it only takes a few lines of code to make your interface pop. This tutorial will teach you five simple tricks for creating stylish UIButtons to make your app standout!


Project Preview

Project Demonstration

Project Setup

In the download that accompanies this tutorial, you’ll find folders entitled “Initial Build” and “Final Build”. Rather than showing all the steps necessary to setup the initial project, you should simply download the attachment and follow along using the project from the “Initial Build” folder.

With the initial project open, go to the ViewController.m file and locate the for loop within the viewDidLoad method. The code snippets from the tips below should be placed within this loop.


Tip #1: Tweak Colors & Gradients

The most fundamental step toward customizing the UIButton class is to adjust the color of the background and title for both the default and highlighted states. The following code snippet sets each button’s background color to black, normal title color to white, and highlighted title color to red:

// Set the button Text Color
[btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[btn setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
// Set the button Background Color
[btn setBackgroundColor:[UIColor blackColor]];

Solid background colors are great, but a subtle gradient can often make the difference between bland and polished. Replace the setBackgroundColor: message above with the following to create a custom gradient:

// Draw a custom gradient
CAGradientLayer *btnGradient = [CAGradientLayer layer];
btnGradient.frame = btn.bounds;
btnGradient.colors = [NSArray arrayWithObjects:
                              (id)[[UIColor colorWithRed:102.0f / 255.0f green:102.0f / 255.0f blue:102.0f / 255.0f alpha:1.0f] CGColor],
                              (id)[[UIColor colorWithRed:51.0f / 255.0f green:51.0f / 255.0f blue:51.0f / 255.0f alpha:1.0f] CGColor],
                             nil];
[btn.layer insertSublayer:btnGradient atIndex:0];

Starting on line 4 above, an NSArray is created with the initial and target gradient colors. Note that the corresponding RGB values must be divided by 255 before being supplied to the colorWithRed:green:blue:alpha: message and that an alpha value of 1.0 represents fully opaque while an alpha value of 0.0 represents fully transparent. Unfortunately, a full explanation of the “magic” above is beyond the scope of this tutorial, but the important thing to remember is to that you simply need to replace the RGB values with the begin/end values you want to use in your own custom gradient.

If all went well, your menu should now look something like this:

Custom Color and Gradient

Not bad, huh? And we’ve only just begun. . .


Tip #2: Round the Corners

Next we want to add a custom corner radius to each UIButton in order to make things look a bit more sleek. Insert the following lines of code to make this happen:

// Round button corners
CALayer *btnLayer = [btn layer];
[btnLayer setMasksToBounds:YES];
[btnLayer setCornerRadius:5.0f];

In line 4 above the corner radius is set to 5.0. Play with this number to increase or decrease how noticeable the corners appear.

You should now have a menu that looks just a bit slicker:

Adding Corner Radius

Tip #3: Add a Stroke Border

Sometimes the small tweaks make all the difference. Add a 1px, black stroke around each button with the following lines of code:

// Apply a 1 pixel, black border
[btnLayer setBorderWidth:1.0f];
[btnLayer setBorderColor:[[UIColor blackColor] CGColor]];

Can you tell the difference? It’s very subtle, but still valuable:

Adding A 1px Border

Tip #4: Use a Custom Font

Now let’s try a more noteworthy tweak. The default system font just isn’t cutting it. The game menu we’re building needs a font that can match the visual aesthetic of the game. A quick search on Google Fonts reveals just a font called Knewave by Tyler Finck that should do the trick. Download Knewave now.

After downloading the Knewave-Regular.ttf file, you’ll need to drag it into the Project Navigator pane in Xcode to add it to your project. Next, open up the Info.plist file. Add a new property list row and type in “Fonts provided by application”. An array should be created automatically. Set the string associated with Item 0 to “Knewave-Regular.ttf”. Double check the name because the value is case sensitive. Save the file.

After making the above modification, your Info.plist file should now look like this:

Plist Entry

Next, you’ll need to add the Knewave-Regular.ttf file to your project’s bundled resources. Select “SleekButtons” from the Project Navigator and then click the “Build Phases” tab. Expand the “Copy Bundle Resources” drop down and then click the plus sign.

Adding to Bundled Resources

At this point, you should be able to begin using the Knewave font in your project! Let’s test that out by jumping back to the ViewController.m file and modifying the viewDidLoad method to set a custom font:

// Set the button Text Color
[btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[btn setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
// Add Custom Font
[[btn titleLabel] setFont:[UIFont fontWithName:@"Knewave" size:18.0f]];
// Draw a custom gradient
CAGradientLayer *btnGradient = [CAGradientLayer layer];
btnGradient.frame = btn.bounds;

Notice that the fontWithName value is specified as “Knewave”, not “Knewave-Regular” as you might expect. This is because there is a difference between the font’s filename and the font’s given name. You’ll need to be sure you use the given name when working with your own fonts.

With the above code in place, the game menu should be complete! Build and run now and you should see something like the following:

Custom Fonts

Tip #5: Optional: Apply a Rotation

While not utilized in the primary design demonstrated by this tutorial, it’s often useful to apply a slight rotation to UIKit elements, particularly UIButton or UIImage objects. Doing so is simple, and can be done with just one line of code.

You can try this out with the code written so far by doing the following:

self.startGameButton.transform = CGAffineTransformMakeRotation(M_PI / 180 * 5.0f);
for(UIButton *btn in buttons)
{
    // Set the button Text Color
    [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [btn setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];

In line 1 above, the constant M_PI is divided by 180 to generate 1 radian, which is then multiplied by 5.0f to result in a rotation of 5 radians. As you will notice if you build and run the project, the above is likely to result in anti-aliasing problems with UIKit elements that are drawn dynamically. Consequently, applying a rotation is more appropriate with a UIButton when the background image property is set and raster graphics are in use (i.e. this works best with PNG files).


Bonus Tip: Use UIButton-Glossy

With the five tips above, you’ve seen how easy it can be to make subtle yet significant tweaks to a UIButton object. However, what if I told you that doing so could be even easier? Meet UIButton-Glossy, an open-source category by George McMullen that automatically applies both a gradient and a glossy finish to UIButton objects.

Implementing UIButton-Glossy in your own project is simple. After you’ve downloaded the UIButton-Glossy.h and UIButton-Glossy.m files and added them to your Xcode project, import the *.h file in the main project view controller, like this:

#import "ViewController.h"
#import "UIButton+Glossy.h"

Now you can instantly apply a cool glossy effect on your buttons with just one line of code: [btn makeGlossy];.

To see this in action, replace the existing view controller code with the following:

for(UIButton *btn in buttons)
{
     // Set the button Text Color
    [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [btn setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
    // Set default backgrond color
    [btn setBackgroundColor:[UIColor blackColor]];
    // Add Custom Font
    [[btn titleLabel] setFont:[UIFont fontWithName:@"Knewave" size:18.0f]];
    // Make glossy
    [btn makeGlossy];
}

Your buttons should now have a glossy finish and the end result should look something like this:

Glossy Finish

Wrap Up

This tutorial has demonstrated multiple techniques for making custom UIButton objects shine. Download the attached project for a glimpse at the full, final source code.

Questions? Comments? Sound off below or message me directly @markhammonds.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • evan

    awesome :D
    wait for titanium edition :D

    • http://mobile.tutsplus.com Mark Hammonds
      Author

      Glad you liked the tutorial, Evan! Doing a Titanium Mobile port would be interesting. Would anyone else reading this be interested in a Titanium version?

  • http://nathanbarry.com Nathan Barry

    Very nice. I like the simple, straightforward approach. Though I would love a follow-up to this that covered how to make this a reusable class. So that the same code wouldn’t have to be rewritten on every view.

    • http://mobile.tutsplus.com Mark Hammonds
      Author

      Hey Nathan, thanks for the feedback.

      Good thought on wrapping this code into a UIButton category or subclass.

      Would anyone else like to see a Quick-Tip followup on how to achieve this?

      • João Carias

        Hi, thank you for this great tutorial!

        And yes, I’d like you to give us a quick-tip on how to wrap this in a category.

      • http://sdbwebsolutions.com/ Serg

        Great tips Mark! I’d also like a QF on this to achieve a custom checkmark button to be used in a form where people can select checkboxes. I know Apple doesn’t encourage the use of those buttons but sometimes people wants to see a UI with these kind of form fields.-

      • http://mobile.tutsplus.com Mark Hammonds
        Author

        Hey Serg, thanks for the feedback! You could create a UIButton that simulates a checkbox with creative use of the setImage:forState: method. Place the background as an empty checkbox until after the touchUpInside event is fired, and then switch to a background image of the checkbox + a check. You’ll need to keep track of the state internally with your ViewController, but that’s not a big deal.

  • Red

    Can it be done in HTML5 / jQuery of buttons. Then the rest in xcode with fonts on Info.plist file in order to use custom font?

    • http://mobile.tutsplus.com Mark Hammonds
      Author

      Hey Red, if you were using something like PhoneGap to develop the menu, you should probably just include the fonts in the www folder and then reference them with CSS using the @font-face property. I wouldn’t think you would need to include them via the plist.

  • Bliitzi

    For some reason I get an error:
    [UIButton makeGlossy]: unrecognized selector sent to instance 0x6a6add0

    That’s funny, because I added the files to the project and also imported the UIButton+Glossy.h File. What’s the problem then?

    • http://mobile.tutsplus.com Mark Hammonds
      Author

      Hey Bliitzi, in the code sample you provide, you’re sending the makeGlossy message directly to the UIButton class. You need to send it to an instance of UIButton instead. So, using the code in my project as an example, you would send it like this: [btn makeGlossy].

  • http://www.billyshih.com Billy Shih

    Awesome tutorial! One small thing people might miss is that you need to import QuartzCore header file when doing this in your own project.

    #import

    • http://mobile.tutsplus.com Mark Hammonds
      Author

      Good point, Billy. Thanks for leaving this note!

  • Emil

    Worked great. The only thing missing is to make the gradient background change when it is highlighted (pressed). Is it even possible to do this when you add the gradient as a sublayer?

    I solved it by using UIGraphicsBeginImageContext() and set that created image as the backgroundImage for my button. But that seems like a “hacky” solution.

    • http://mobile.tutsplus.com Mark Hammonds
      Author

      Hi Emil,

      Good point about changing the background gradient on press. Not sure why I didn’t think to include this in the tutorial, but it’s relatively simple to do. From my sample code attached, just add a custom UIControlEventTouchDown and UIControlEventTouchUpInside event to each button in the for loop, like this:

      [btn addTarget:self action:@selector(setPressedGradient:) forControlEvents:UIControlEventTouchDown];

      [btn addTarget:self action:@selector(setUnpressedGradient:) forControlEvents:UIControlEventTouchUpInside];

      For each of the custom press methods, you’ll need to grab the layer at index 0 (i.e. where it was initially placed it in the tutorial code), and then change the colors property. Take a look:

      -(void)setPressedGradient:(id)sender
      {
      UIButton *btnPressed = (UIButton *)sender;
      CAGradientLayer *btnLayer = [[btnPressed.layer sublayers] objectAtIndex:0];
      btnLayer.colors = [NSArray arrayWithObjects:
      (id)[[UIColor colorWithRed:225.0f / 255.0f green:225.0f / 255.0f blue:225.0f / 255.0f alpha:1.0f] CGColor],
      (id)[[UIColor colorWithRed:130.0f / 255.0f green:130.0f / 255.0f blue:130.0f / 255.0f alpha:1.0f] CGColor],
      nil];
      }

      -(void)setUnpressedGradient:(id)sender
      {
      UIButton *btnUnpressed = (UIButton *)sender;
      CAGradientLayer *btnLayer = [[btnUnpressed.layer sublayers] objectAtIndex:0];
      btnLayer.colors = [NSArray arrayWithObjects:
      (id)[[UIColor colorWithRed:102.0f / 255.0f green:102.0f / 255.0f blue:102.0f / 255.0f alpha:1.0f] CGColor],
      (id)[[UIColor colorWithRed:51.0f / 255.0f green:51.0f / 255.0f blue:51.0f / 255.0f alpha:1.0f] CGColor],
      nil];

      }

      Of course, in your own projects, you would probably want to handle things a bit differently. For example, rather than setting the UIControlEventTouchUpInside to setUnpressedGradient directly, you would have it set to whatever your custom logic is, and at the beginning of your custom button event code you can simply call the setUnpressedGradient method before moving on to your own logic. You could also refactor all of this to nicely package the aesthetic into a UIButton subclass or category, which would be significantly more robust. If I get around to doing this in the near future, I’ll add the class to Github and post the link.

      Hope this helps!

      -Mark

  • http://supertecnoboff.co.uk Daniel Sadjadian

    Nice tutorial. Really helpful :)

  • Billy

    Is there a way to use an image with text using these buttons? I tried adding an additional layer with an image but couldn’t get it to work.

    Any ideas?

  • Nathan

    Quick Question.. Does this work with the latex release of Xcode and IO6?

    I am fairly new to Xcode(I’m a C# Developer tho). I am trying to use this tutorial in a static class that all my view controllers can call and pass in an array of buttons. Everything works except for the gradient.

    I tried the tutorial “as-is” and it still wouldn’t apply the gradient.

    • http://mobile.tutsplus.com Mark Hammonds
      Author

      Hey Nathan, sounds like there might be something else going on in your project. I just downloaded the attached source file and ran the finished product on both the iOS 6.0 and iOS 5.1 simulators with Xcode 4.5 and everything works as intended. Be sure you are importing the QuartzCore framework in your project, and also check the Xcode project under the “FinalBuild” folder as a reference.

  • waldorf

    and where is this code supposed to reside? no mention in article for newbies like me!

    • waldorf

      never mind, I re-read it and you did mention where it dgoes, my apologies!

  • taylornrolyat

    What code would I use for a UILabel instead of a UIButton?

    • taylornrolyat

      never mind, figured it out

      [labelScore setTextColor:[UIColor whiteColor]];
      [labelScore setFont:[UIFont fontWithName:@"example" size:18.0f]];

  • Derek Salerno

    I went to hell and back trying to figure out how to add a custom font to the buttons in my application. I probably looked at 100 different posts on stackoverflow.com and came so close to smashing my macbook pro, I shudder to think of it. The one thing I was constantly missing was the step of adding the font to my bundle resources, which I finally found on this page. Thank you!!!!!

  • Mike

    Thanks. very helpful.

  • http://profiles.google.com/kyle.luchinski Kyle Luchinski

    Awesome! Everything works great, but I get a SIGABRT when I use [button makeGlossy]; ..anyone else getting this in 6.1?;

  • Guest

    Great tutorial! Thanks for sharing!

  • http://twitter.com/kenbarlo Ken Barlo

    Worked great! Thanks for sharing, this came right at the right time. I was looking for a tutorial like this.

  • Kevin Houston

    Hoping for some good Karma out of posting this tip. ;) If you are trying to make use of the UIButton+Glossy code with Autolayout turned on then the call to [btn makeGlossy]; needs to happen in viewDidLayoutSubviews. I was trying to call it from viewWillAppear and getting only a clear button with a background colored border because the UIButton’s size had not been set yet. See http://stackoverflow.com/a/14147303 for further info.