Skip to content

Instantly share code, notes, and snippets.

@henrik
Created April 1, 2010 20:08
Show Gist options
  • Save henrik/352307 to your computer and use it in GitHub Desktop.
Save henrik/352307 to your computer and use it in GitHub Desktop.
Core Graphics rounded rectangle with gradient background on the iPhone, NSTokenField/NSTokenFieldCell style. Kind of like in Mail.app.

Rounded rectangle with gradient background on the iPhone, NSTokenFieldCell style.

Screenshot

Unlike my previous implementation, this one is drawn inside a single view using Core Graphics. It can thus be used for optimized, fast-scrolling cells per Apple's TableViewSuite sample.

The gradient shades are changed from that implementation, too, and the border itself is gradiented (by drawing a smaller rectangle inside a larger one that becomes the border).

You need to include the uicolor-utilities category by Ars Technica.

// ViewContainingToken.h
// By Henrik Nyh <http://henrik.nyh.se> 2010-04-01 under the MIT license.
// http://gist.github.com/352307
#import <UIKit/UIKit.h>
@interface ViewContainingToken : UIView {
}
@end
#import "ViewContainingToken.h"
// Include this: http://github.com/ars/uicolor-utilities/
#import "UIColor-Expanded.h"
@interface ViewContainingToken (Private)
- (void)drawTokenInRect:(CGRect)rect color:(UIColor *)color text:(NSString *)text;
@end
@implementation ViewContainingToken
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
self.opaque = YES;
self.backgroundColor = [UIColor whiteColor];
}
return self;
}
#pragma mark -
- (void)drawRect:(CGRect)rect {
[self drawTokenInRect:CGRectMake(7, 12, 62, 22) color:[UIColor purpleColor] text:@"Hello!"];
}
#pragma mark -
void AKCGGradientRoundedRectCreate(CGContextRef context, CGRect rect,
CGColorSpaceRef colorspace, CGColorRef firstColor, CGColorRef lastColor);
- (void)drawTokenInRect:(CGRect)rect color:(UIColor *)color text:(NSString *)text {
// Rounded rectangle
UIColor *bottomColor = color;
UIColor *topColor = [bottomColor colorByMultiplyingBy:1.07];
UIColor *borderTopColor = [bottomColor colorByMultiplyingBy:0.95];
UIColor *borderBottomColor = [bottomColor colorByMultiplyingBy:0.85];
// We draw a lighter gradient rectangle inside a darker gradient rectangle to get a gradient border.
CGRect outerRect = rect;
CGRect innerRect = CGRectInset(outerRect, 1, 1);
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
AKCGGradientRoundedRectCreate(context, outerRect, colorspace, borderTopColor.CGColor, borderBottomColor.CGColor);
AKCGGradientRoundedRectCreate(context, innerRect, colorspace, topColor.CGColor, bottomColor.CGColor);
CGColorSpaceRelease(colorspace);
// Text inside the rectangle
UIFont *labelFont = [UIFont systemFontOfSize:12];
CGRect labelRect = CGRectInset(innerRect, 3, 2);
CGRect labelShadowRect = CGRectOffset(labelRect, 0, 1);
// Text shadow
[[UIColor whiteColor] set];
[text drawInRect:labelShadowRect
withFont:labelFont
lineBreakMode:UILineBreakModeMiddleTruncation
alignment:UITextAlignmentCenter];
// Text proper
[[UIColor blackColor] set];
[text drawInRect:labelRect
withFont:labelFont
lineBreakMode:UILineBreakModeMiddleTruncation
alignment:UITextAlignmentCenter];
CGMutablePathRef AKCGRoundedRectCreate(CGRect rect, CGFloat radius);
void AKCGGradientRoundedRectCreate(CGContextRef context, CGRect rect,
CGColorSpaceRef colorspace, CGColorRef firstColor, CGColorRef lastColor) {
CGFloat radius = rect.size.height/2;
CGMutablePathRef path = AKCGRoundedRectCreate(rect, radius);
CGContextAddPath(context, path);
CGContextSaveGState(context);
CGContextClip(context);
CGColorRef colors[] = {firstColor, lastColor};
CFArrayRef colorsArray = CFArrayCreate(NULL, (void *)colors, 2, &kCFTypeArrayCallBacks);
CGGradientRef gradient = CGGradientCreateWithColors(colorspace, colorsArray, NULL);
CGPoint startPoint = rect.origin;
CGPoint endPoint = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CFRelease(colorsArray);
CGGradientRelease(gradient);
CGContextRestoreGState(context);
CGPathRelease(path);
}
CGMutablePathRef AKCGRoundedRectCreate(CGRect rect, CGFloat radius) {
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, NULL, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect));
CGPathAddArc(thePath, NULL, CGRectGetMaxX(rect) - radius, CGRectGetMinY(rect) + radius, radius, 3 * M_PI / 2, 0, 0);
CGPathAddArc(thePath, NULL, CGRectGetMaxX(rect) - radius, CGRectGetMaxY(rect) - radius, radius, 0, M_PI / 2, 0);
CGPathAddArc(thePath, NULL, CGRectGetMinX(rect) + radius, CGRectGetMaxY(rect) - radius, radius, M_PI / 2, M_PI, 0);
CGPathAddArc(thePath, NULL, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect) + radius, radius, M_PI, 3 * M_PI / 2, 0);
CGPathCloseSubpath(thePath);
return thePath;
}
@end
@jianpx
Copy link

jianpx commented Jul 18, 2013

the effect image is missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment