Core Graphics Tutorial: Glossy Buttons

Ray Wenderlich

This post is also available in: Japanese, Korean

Create your own cool and flexible buttons from scratch!

Create your own cool and flexible buttons from scratch!

Update 4/18/2013 Fully updated for Xcode 4.6, and ARC. (original post by Ray Wenderlich, update by Brian Moakley).

Welcome back to another tutorial in the Core Graphics tutorial series! In this tutorial series, you learn how to get started with Core Graphics – with practical examples.

In tutorials one, two, and three, you learned how to customize a table view from start to finish – just with Core Graphics.

In this Core Graphics tutorial, you’re going to tackle a different practical example – how to customize a UIButton.

In the process, you’ll learn how to draw rounded rects, how to easily tint your Core Graphics drawings, and reinforce some of the concepts you’ve already covered.

As Alex Curylo from Under The Bridge has mentioned many times, there are a lot of good options out there for how to customize your UIButtons already. My personal favorite for quick and easy button making is Button Maker by Dermot Daly, by the way.

But I think what’s been missing in this discussion is a detailed Core Graphics tutorial for how to customize the buttons yourself, from start to finish. It’s pretty simple, and this way you can get the exact look you’re going for in your app.

So let’s get started and make some buttons!

Getting Started

Start up Xcode and create a new project (File\New\Project…). Select the iOS\Application\Single View Application template and click Next.

Single View Application

Enter CoolButton for the Product Name, enter an Organization Name (anything will do), enter a Company Identifier prefix such as com.mycompany, select iPhone for Devices, and checkmark Use Storyboards and Use Automatic Reference Counting.

Project Settings

Next go to File\New\File…, choose the iOS\Cocoa Touch Class\Objective-C class template, and click Next. In the next menu, enter the name CoolButton as the class name. In the subclass field, type UIButton. Click Next then Create.

Open CoolButton.h and replace with the following:

#import <UIKit/UIKit.h>
 
@interface CoolButton : UIButton
 
@property  (nonatomic, assign) CGFloat hue;
@property  (nonatomic, assign) CGFloat saturation;
@property  (nonatomic, assign) CGFloat brightness;
 
@end

Here you create three properties that you’ll use to customize the color’s hue, saturation, and brightness.

Then open CoolButton.m and replace it with the following:

#import "CoolButton.h"
 
@implementation CoolButton
 
-(id) initWithCoder:(NSCoder *)aDecoder 
{
    if ((self = [super initWithCoder:aDecoder])) {
        self.opaque = NO;
        self.backgroundColor = [UIColor clearColor];
        _hue = 0.5;
        _saturation = 0.5;
        _brightness = 0.5;
    }
    return self;
}
 
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIColor * color = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:self.brightness alpha:1.0];
    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, self.bounds);
}
 
-(void) setHue:(CGFloat)hue
{
    _hue = hue;
    [self setNeedsDisplay];
}
 
-(void) setSaturation:(CGFloat)saturation
{
    _saturation = saturation;
    [self setNeedsDisplay];
}
 
-(void) setBrightness:(CGFloat)brightness
{
    _brightness = brightness;
    [self setNeedsDisplay];
}
 
@end

Here you are just initializing the variables and filling the whole thing with some pre-configured color to make sure everything’s working OK to start.

Note that you’re using a different constructor to make the color this time – rather than colorWithRed:green:blue, you use colorWithHue:saturation:brightness. This will make things a bit easier for you later on.

The last thing you do here is override the setters for the hue, saturation, and brightness properties so you call setNeedsDisplay when they are called. This will force your view to redraw when the user changes the color of the button.

Now switch over to ViewController.h and replace it with the following:

#import <UIKit/UIKit.h>
 
@class CoolButton;
 
@interface ViewController : UIViewController
 
@property (nonatomic, strong) IBOutlet CoolButton * coolButton;
 
- (IBAction)hueValueChanged:(id)sender;
- (IBAction)saturationValueChanged:(id)sender;
- (IBAction)brightnessValueChanged:(id)sender;
 
@end

Here you’re declaring a reference to the button (which you’ll make in Interface Builder) and some callbacks for when the configuratoin slider values change (which you’ll also add in Interface Builder).

So go ahead and do that now. Open up MainStoryboard.storyboard, and drag a button, 3 labels, and 3 sliders onto the view. Also, deselect the Use Autolayout checkbox. It should look something like this:

Next, change the class of the UIButton to be a CoolButton by going to the Identity Inspector and changing the Class dropdown to CoolButton:

Also, make sure the Attributes Inspector is selected, and switch the drawing type of the Button to Custom to remove the default rounded corners of the button.

Then, control-drag from ViewController in the View Controller Scene panel on the left to the button and connect it to the coolButton outlet. Similarly, control-drag from each slider up to ViewController in the View Controller Scene panel on the left to connect it to the appropriate value changed callback.

Before leaving the storyboard, double click on the button to select the word “Button”, then press the delete key to delete the text.

One last thing before you try it out. First import the CoolButton class in ViewController.m. The top of the file should look like this:

#import "ViewController.h"
#import "CoolButton.h"

Next, switch to ViewController.m and implement the slider value changed callbacks:

- (IBAction)hueValueChanged:(id)sender
{
    UISlider * slider = (UISlider *) sender;
    self.coolButton.hue = slider.value;
}
 
- (IBAction)saturationValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    self.coolButton.saturation = slider.value;
}
 
- (IBAction)brightnessValueChanged:(id)sender
{
    UISlider * slider = (UISlider *)sender;
    self.coolButton.brightness = slider.value;
}

Note that by default UISliders are set to go from 0.0 to 1.0 – which is perfect for your hue, saturation, and brightness values, which also range from 0.0 to 1.0, so you can just set them directly.

Build and run the project, and if all works well you should be able to play around with the sliders to fill the button with various colors:

Drawing Rounded Rectangles

It’s true that you can have square buttons, but these days it’s fashionable to have rounded rectangle buttons for the most part instead.

Note: Since the time of writing this article, flat rectangles are back in style, like in the Windows 8 user interface. Go figure! ;]

In the last Core Graphics tutorial, you learned how to draw arcs using the CGContextAddArc API. So you could definitely use that to draw an arc at each corner, and draw lines to connect them, based on stuff you already know.

But there’s an even easier way, where you don’t have to do quite so much math, and that actually fits in really well with drawing rounded rectangles. It’s the CGContextAddArcToPoint API.

The CGContextAddArcToPoint API lets you specify the arc to draw by specifying two tangent lines and a radius. The following diagram from the Quartz2D Programming Guide shows it pretty well:

CGContextAddArcToPoint Diagram

So for the case of a rectangle, you obviously know the tangent lines for each arc you want to draw – they are just the edges of the rectangle! And you can specify the radius based on how rounded you want the rectangle to be – the larger, the more rounded.

The other neat thing about this function is if the current point in the path isn’t set to where you tell the arc to begin drawing, it will draw a line from the current point to the beginning of the path. So you can use this as a shortcut to draw a rounded rectangle in just a couple calls.

Since you’re going to create a bunch of rounded rects in this Core Graphics tutorial and in the future, add a helper function to Common.h/m to create a path for a rounded rect, given a rectangle.

If you don’t have it already, download Common.h/m where you left it off last time, and add it to your project.

Then add the following to Common.h:

CGMutablePathRef createRoundedRectForRect(CGRect rect, CGFloat radius);

And the following to the bottom of Common.m:

CGMutablePathRef createRoundedRectForRect(CGRect rect, CGFloat radius) 
{ 
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, CGRectGetMidX(rect), CGRectGetMinY(rect));
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMinY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect), radius);
    CGPathCloseSubpath(path);
 
    return path;        
}

The above code is drawing the rounded rect in the following order:

How to draw a rounded rect with Core Graphics

  1. Move to the center of the top line segment.
  2. Add an arc for the upper right corner. Before drawing an arc, CGPathAddArcToPoint will draw a line from the current position (middle of the rect) to the beginning of the arc for you.
  3. Similarly, add an arc for the lower right corner and the connecting line.
  4. Similarly, add an arc for the lower left corner and the connecting line.
  5. Similarly, add an arc for the upper left corner and the connecting line.
  6. Then connect the ending point of the arc with the starting point with CGPathCloseSubpath.

Also note in the above that you will use some more of the useful helper methods from CGGeometry.h to pull out various locations in the rectangle you’re provided.

Ok let’s see how this works! Open up CoolButton.m and make the following modifications:

// At top of file
#import "Common.h"
 
// Replace the contents of drawRect with the following:
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
 
    UIColor * outerTop = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:self.brightness alpha:1.0];
    UIColor * shadowColor = [UIColor colorWithRed:0.2 green:0.2  blue:0.2 alpha:0.5];
 
    CGFloat outerMargin = 5.0f;
    CGRect outerRect = CGRectInset(self.bounds, outerMargin, outerMargin);
    CGMutablePathRef outerPath = createRoundedRectForRect(outerRect, 6.0);
 
    if (self.state != UIControlStateHighlighted) {
        CGContextSaveGState(context);
        CGContextSetFillColorWithColor(context, outerTop.CGColor);
        CGContextSetShadowWithColor(context, CGSizeMake(0, 2), 3.0, shadowColor.CGColor);
        CGContextAddPath(context, outerPath);
        CGContextFillPath(context);
        CGContextRestoreGState(context);
    }
}

Ok, so you define your two colors, then you use CGRectInset to get a slightly smaller rectangle (5 pixels on each side) where you’ll draw the rounded rect. You make it smaller so you have space to draw a shadow on the outside.

Next, you call the function you just wrote to create a path for your rounded rect. You then set the fill color and shadow, add the path to your context, and call CGContextFillPath to fill it with your current color.

Note you only want to run the code if your button isn’t currently highlighted (i.e. being tapped upon).

Build and run the app, and if all works well you should see the following:

Styling Your Button

Ok great, you have something that looks somewhat like a button now. But I bet you can do even better!

Open up CoolButton.m and make the following mods:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
 
    UIColor * blackColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    UIColor *  highlightStart = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.4];
    UIColor *  highlightStop = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.1];
    UIColor *  shadowColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.5];
 
    UIColor * outerTop = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:1.0*self.brightness alpha:1.0];
    UIColor * outerBottom = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.80*self.brightness alpha:1.0];
    UIColor * innerStroke = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.80*self.brightness alpha:1.0];
    UIColor * innerTop = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.90*self.brightness alpha:1.0];
    UIColor * innerBottom = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.70*self.brightness alpha:1.0];
 
    ...
 
    CGContextSaveGState(context);
    CGContextAddPath(context, outerPath);
    CGContextClip(context);
    drawGlossAndGradient(context, outerRect, outerTop.CGColor, outerBottom.CGColor);
    CGContextRestoreGState(context);
}

First thing you do is set up a bunch of colors that you’ll use later. There are a few generic colors, and then several colors based on the passed in parameters. Your base color is exactly how you’re set up, then you have several colors set up to be darker than the current color, to varying degress.

If you define your colors in this way, it makes it really easy to change the colors of your views, which can be quite handy for reusing code!

The next thing you do is clip to your rounded rect, and fill it with a gradient (rather than a single color). Build and run and your button is starting to look better:

Button Styling - Update 1

Now add an inner path that has a slightly different gradient than the outer path, to create a bevel-type effect. Make the following mods to CoolButton.m:

- (void)drawRect:(CGRect)rect
{
    ...
    CGMutablePathRef outerPath = createRoundedRectForRect(outerRect, 6.0);  //Previous Code
 
    CGFloat innerMargin = 3.0f;
    CGRect innerRect = CGRectInset(outerRect, innerMargin, innerMargin);
    CGMutablePathRef innerPath = createRoundedRectForRect(innerRect, 6.0);
 
    ...
    CGContextRestoreGState(context);  // Previous Code at Bottom
 
    CGContextSaveGState(context);
    CGContextAddPath(context, innerPath);
    CGContextClip(context);
    drawGlossAndGradient(context, innerRect, innerTop.CGColor, innerBottom.CGColor);
    CGContextRestoreGState(context);
}

Here you shrink the rectangle again with CGRectInset, then get a rounded rect for that and run a gradient over it. Build and run and there’s a subtle improvement:

Button Styling - Update 2

Now add a very subtle highlight on the top, if the button is selected. Make some more mods to CoolButton.m:

- (void)drawRect:(CGRect)rect
{
    ...
    CGMutablePathRef innerPath = createRoundedRectForRect(innerRect, 6.0); // Previous Code
 
    CGFloat highlightMargin = 2.0f;
    CGRect highlightRect = CGRectInset(outerRect, highlightMargin, highlightMargin);
    CGMutablePathRef highlightPath = createRoundedRectForRect(highlightRect, 6.0);
 
    ...
    CGContextRestoreGState(context); // Previous Code at Bottom
 
    if (self.state != UIControlStateHighlighted) {
        CGContextSaveGState(context);
        CGContextSetLineWidth(context, 4.0);
        CGContextAddPath(context, outerPath);
        CGContextAddPath(context, highlightPath);
        CGContextEOClip(context);
        drawLinearGradient(context, outerRect, highlightStart.CGColor, highlightStop.CGColor);
        CGContextRestoreGState(context);
    }
}

You’re basically creating another rounded rect slightly smaller than the outerRect, and filling the area between the two rectangles with an alpha highlight gradient, using the Even-Odd Clip technique from last Core Graphics tutorial.

Build and run to check it out – it’s a very subtle touch so you might not notice it:

Button Styling - Update 3

Time to wrap it up. Add the following code to the bottom of drawRect:

- (void)drawRect:(CGRect)rect
{
    ...
        CGContextRestoreGState(context);
    }  // Previous Code at Bottom
 
    CGContextSaveGState(context);
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, blackColor.CGColor);
    CGContextAddPath(context, outerPath);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
 
    CGContextSaveGState(context);
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, innerStroke.CGColor);
    CGContextAddPath(context, innerPath);
    CGContextClip(context);
    CGContextAddPath(context, innerPath);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
 
    CFRelease(outerPath);
    CFRelease(innerPath);
    CFRelease(highlightPath);
}

All you do here is stroke the outer path with black (2 points to avoid the 1px issues), and the inner path with a 1 point stroke.

“OMGBBQ”, you may say, “that is a 2 point stroke, not a 1 point stroke!” Well, you’re using a different technique to solve the 1px issue here – the “clipping mask” technique referred to earlier. Basically you set the stroke to be 2 points, and then clip off the outside region.

At the end, you release the paths you’ve created. If you had trouble following along, here is the complete method so far:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
 
    UIColor *  blackColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    UIColor *  highlightStart = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.4];
    UIColor *  highlightStop = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.1];
    UIColor *  shadowColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.5];
 
    UIColor * outerTop = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:1.0*self.brightness alpha:1.0];
    UIColor * outerBottom = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.80*self.brightness alpha:1.0];
    UIColor * innerStroke = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.80*self.brightness alpha:1.0];
    UIColor * innerTop = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.90*self.brightness alpha:1.0];
    UIColor * innerBottom = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.70*self.brightness alpha:1.0];
 
    CGFloat outerMargin = 5.0f;
    CGRect outerRect = CGRectInset(self.bounds, outerMargin, outerMargin);
    CGMutablePathRef outerPath = createRoundedRectForRect(outerRect, 6.0);
 
    CGFloat innerMargin = 3.0f;
    CGRect innerRect = CGRectInset(outerRect, innerMargin, innerMargin);
    CGMutablePathRef innerPath = createRoundedRectForRect(innerRect, 6.0);
 
    CGFloat highlightMargin = 2.0f;
    CGRect highlightRect = CGRectInset(outerRect, highlightMargin, highlightMargin);
    CGMutablePathRef highlightPath = createRoundedRectForRect(highlightRect, 6.0);
 
    if (self.state != UIControlStateHighlighted) {
        CGContextSaveGState(context);
        CGContextSetFillColorWithColor(context, outerTop.CGColor);
        CGContextSetShadowWithColor(context, CGSizeMake(0, 2), 3.0, shadowColor.CGColor);
        CGContextAddPath(context, outerPath);
        CGContextFillPath(context);
        CGContextRestoreGState(context);
    }
 
    CGContextSaveGState(context);
    CGContextAddPath(context, outerPath);
    CGContextClip(context);
    drawGlossAndGradient(context, outerRect, outerTop.CGColor, outerBottom.CGColor);
    CGContextRestoreGState(context);
 
    CGContextSaveGState(context);
    CGContextAddPath(context, innerPath);
    CGContextClip(context);
    drawGlossAndGradient(context, innerRect, innerTop.CGColor, innerBottom.CGColor);
    CGContextRestoreGState(context);
 
    if (self.state != UIControlStateHighlighted) {
        CGContextSaveGState(context);
        CGContextSetLineWidth(context, 4.0);
        CGContextAddPath(context, outerPath);
        CGContextAddPath(context, highlightPath);
        CGContextEOClip(context);
        drawLinearGradient(context, outerRect, highlightStart.CGColor, highlightStop.CGColor);
        CGContextRestoreGState(context);
    }
 
    CGContextSaveGState(context);
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, blackColor.CGColor);
    CGContextAddPath(context, outerPath);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
 
    CGContextSaveGState(context);
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, innerStroke.CGColor);
    CGContextAddPath(context, innerPath);
    CGContextClip(context);
    CGContextAddPath(context, innerPath);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
 
    CFRelease(outerPath);
    CFRelease(innerPath);
    CFRelease(highlightPath);
}

Build and run the app, and check out your button now!

Button Styling - Update 4

It’s amazing what a few strokes can do!

And hey – get your mind out of the gutter :P

Highlighting the Button

Your button looks pretty cool, but doesn’t act like a button. There’s no indication when the button is pressed or not.

Luckily, Jeff LaMarche demonstrates how to handle this in one of his posts on the subject.

The basic idea is you need to override the touch events to tell your button to redisplay itself, since it might need an update due to being selected.

So make the following modifications to CoolButton.m:

// Add the following methods to the bottom
- (void)hesitateUpdate
{
    [self setNeedsDisplay];
}
 
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [super touchesBegan:touches withEvent:event];
    [self setNeedsDisplay];
}
 
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    [self setNeedsDisplay];
 
}
 
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [super touchesCancelled:touches withEvent:event];
    [self setNeedsDisplay];
    [self performSelector:@selector(hesitateUpdate) withObject:nil afterDelay:0.1];
}
 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [self setNeedsDisplay];
    [self performSelector:@selector(hesitateUpdate) withObject:nil afterDelay:0.1];
}

Build and run the project, and you’ll see that there’s a difference as you tap the button now – the highlight and tap disappears. But let’s make it a bit better with one more change to drawRect:

- (void)drawRect:(CGRect)rect
{
    CGFloat actualBrightness = self.brightness;
    if (self.state == UIControlStateHighlighted) {
        actualBrightness -= 0.10;
    }
 
    CGContextRef context = UIGraphicsGetCurrentContext();  // Previous Code
 
    ...
 
    // self.brightness is now acutalBrightness    
    UIColor * outerTop = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:1.0*actualBrightness alpha:1.0];
    UIColor * outerBottom = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.80*actualBrightness alpha:1.0];
    UIColor * innerStroke = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.80*actualBrightness alpha:1.0];
    UIColor * innerTop = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.90*actualBrightness alpha:1.0];
    UIColor * innerBottom = [UIColor colorWithHue:self.hue saturation:self.saturation brightness:0.70*actualBrightness alpha:1.0];

Build and run and now the button should look pretty good when you tap it!

Tapped Button

Where To Go From Here?

Here is a sample project with all of the code you developed in the above Core Graphics tutorial.

Now that you’ve gone through all of the steps to create custom buttons from scratch, you should be intimately familiar with how to customize every aspect of the button to your liking for your project’s style!

Next up in the Core Graphics tutorial series you’ll learn how to use patterns for a cool effect!.

Ray Wenderlich

Ray is an indie software developer currently focusing on iPhone and iPad development, and the administrator of this site. He’s the founder of a small iPhone development studio called Razeware, and is passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

User Comments

5 Comments

  • Great tutorial.

    "enter the name CoolButton as the class name. In the subclass field, type UIView."
    Should UIView be changed to UIButton?
    tomneo2004
  • Good catch, fixed!
    rwenderlich
  • Highlighting the Button

    To indicate when the button is pressed or not use this method:

    Code: Select all
    - (void)setHighlighted:(BOOL)highlighted
    {
       [self setNeedsDisplay];
       [super setHighlighted:highlighted];
    }
    algashev
  • The highlighting code has a problem. When you put a button in a UITableViewCell, touch it and push in another view controller, then pop it. If you do this quickly, the button will keep highlighted. While using algashev's code seems correct.
    Hokuang
  • Any chance somebody updates this tutorial series to Swift?

    Regards,

    Enrique.
    epinaud

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Non-Gaming tutorial votes. This week: Non-Gaming!

    Loading ... Loading ...

Last week's winner: Best iOS Animations in 2014. [Read Now]!

Suggest a Tutorial - Past Results

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in October: Xcode 6 Tips and Tricks!

Sign Up - October

Our Books

Our Team

Tutorial Team

... 49 total!

Update Team

  • Andy Pereira
  • Zouhair Mahieddine

... 15 total!

Editorial Team

  • Alexis Gallagher

... 22 total!

Code Team

  • Orta Therox

... 3 total!

Translation Team

  • Di Peng
  • David Xie

... 32 total!

Subject Matter Experts

  • Richard Casey

... 4 total!