Instantly share code, notes, and snippets.
Created
May 28, 2012 11:55
-
Star
(1)
1
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save kaiix/2818762 to your computer and use it in GitHub Desktop.
Gloss gradients button for ios
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GlossGradientButton.h | |
// iOS version of gloss gradients button | |
// original version for Mac OSX http://cocoawithlove.com/2008/09/drawing-gloss-gradients-in-coregraphics.html | |
// | |
#import <UIKit/UIKit.h> | |
@interface GlossGradientButton : UIButton { | |
UIColor *buttonColor_; | |
} | |
@property(nonatomic, retain) UIColor *buttonColor; | |
- (id)initWithFrame:(CGRect)frame color:(UIColor *)color; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GlossGradientButton.m | |
// iOS version of gloss gradients button | |
// original version for Mac OSX http://cocoawithlove.com/2008/09/drawing-gloss-gradients-in-coregraphics.html | |
// | |
#import "GlossGradientButton.h" | |
float perceptualGlossFractionForColor(float *inputComponents) | |
{ | |
const float REFLECTION_SCALE_NUMBER = 0.2; | |
const float NTSC_RED_FRACTION = 0.299; | |
const float NTSC_GREEN_FRACTION = 0.587; | |
const float NTSC_BLUE_FRACTION = 0.114; | |
float glossScale = | |
NTSC_RED_FRACTION * inputComponents[0] + | |
NTSC_GREEN_FRACTION * inputComponents[1] + | |
NTSC_BLUE_FRACTION * inputComponents[2]; | |
glossScale = pow(glossScale, REFLECTION_SCALE_NUMBER); | |
return glossScale; | |
} | |
typedef struct | |
{ | |
float color[4]; | |
float caustic[4]; | |
float expCoefficient; | |
float expScale; | |
float expOffset; | |
float initialWhite; | |
float finalWhite; | |
} GlossParameters; | |
static void glossInterpolation(void *info, const float *input, | |
float *output) | |
{ | |
GlossParameters *params = (GlossParameters *)info; | |
float progress = *input; | |
if (progress < 0.5) | |
{ | |
progress = progress * 2.0; | |
progress = | |
1.0 - params->expScale * (expf(progress * -params->expCoefficient) - params->expOffset); | |
float currentWhite = progress * (params->finalWhite - params->initialWhite) + params->initialWhite; | |
output[0] = params->color[0] * (1.0 - currentWhite) + currentWhite; | |
output[1] = params->color[1] * (1.0 - currentWhite) + currentWhite; | |
output[2] = params->color[2] * (1.0 - currentWhite) + currentWhite; | |
output[3] = params->color[3] * (1.0 - currentWhite) + currentWhite; | |
} | |
else | |
{ | |
progress = (progress - 0.5) * 2.0; | |
progress = params->expScale * | |
(expf((1.0 - progress) * -params->expCoefficient) - params->expOffset); | |
output[0] = params->color[0] * (1.0 - progress) + params->caustic[0] * progress; | |
output[1] = params->color[1] * (1.0 - progress) + params->caustic[1] * progress; | |
output[2] = params->color[2] * (1.0 - progress) + params->caustic[2] * progress; | |
output[3] = params->color[3] * (1.0 - progress) + params->caustic[3] * progress; | |
} | |
} | |
void getComponents(UIColor *color, float *output) | |
{ | |
[color getRed:&output[0] green:&output[1] blue:&output[2] alpha:&output[3]]; | |
} | |
void perceptualCausticColorForColor(float *inputComponents, float *outputComponents) | |
{ | |
const float CAUSTIC_FRACTION = 0.60; | |
const float COSINE_ANGLE_SCALE = 1.4; | |
const float MIN_RED_THRESHOLD = 0.95; | |
const float MAX_BLUE_THRESHOLD = 0.7; | |
const float GRAYSCALE_CAUSTIC_SATURATION = 0.2; | |
UIColor *source = [UIColor colorWithRed:inputComponents[0] | |
green:inputComponents[1] | |
blue:inputComponents[2] | |
alpha:inputComponents[3]]; | |
float hue, saturation, brightness, alpha; | |
[source getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha]; | |
float targetHue, targetSaturation, targetBrightness; | |
[[UIColor yellowColor] getHue:&targetHue saturation:&targetSaturation brightness:&targetBrightness alpha:&alpha]; | |
if (saturation < 1e-3) { | |
hue = targetHue; | |
saturation = GRAYSCALE_CAUSTIC_SATURATION; | |
} | |
if (hue > MIN_RED_THRESHOLD) { | |
hue -= 1.0; | |
} else if (hue > MAX_BLUE_THRESHOLD) { | |
[[UIColor magentaColor] getHue:&targetHue saturation:&targetSaturation brightness:&targetBrightness alpha:&alpha]; | |
} | |
float scaledCaustic = CAUSTIC_FRACTION * 0.5 * (1.0 + cos(COSINE_ANGLE_SCALE * M_PI * (hue - targetHue))); | |
UIColor *targetColor = [UIColor colorWithHue:hue * (1.0 - scaledCaustic) + targetHue * scaledCaustic | |
saturation:saturation | |
brightness:brightness * (1.0 - scaledCaustic) + targetBrightness * scaledCaustic | |
alpha:inputComponents[3]]; | |
getComponents(targetColor, outputComponents); | |
} | |
void DrawGlossGradient(CGContextRef context, UIColor *color, CGRect inRect) | |
{ | |
const float EXP_COEFFICIENT = 1.2; | |
const float REFLECTION_MAX = 0.60; | |
const float REFLECTION_MIN = 0.20; | |
GlossParameters params; | |
params.expCoefficient = EXP_COEFFICIENT; | |
params.expOffset = expf(-params.expCoefficient); | |
params.expScale = 1.0 / (1.0 - params.expOffset); | |
getComponents(color, params.color); | |
perceptualCausticColorForColor(params.color, params.caustic); | |
float glossScale = perceptualGlossFractionForColor(params.color); | |
params.initialWhite = glossScale * REFLECTION_MAX; | |
params.finalWhite = glossScale * REFLECTION_MIN; | |
static const float input_value_range[2] = {0, 1}; | |
static const float output_value_ranges[8] = {0, 1, 0, 1, 0, 1, 0, 1}; | |
CGFunctionCallbacks callbacks = {0, glossInterpolation, NULL}; | |
CGFunctionRef gradientFunction = CGFunctionCreate( | |
(void *)¶ms, | |
1, // number of input values to the callback | |
input_value_range, | |
4, // number of components (r, g, b, a) | |
output_value_ranges, | |
&callbacks); | |
CGPoint startPoint = CGPointMake(CGRectGetMinX(inRect), CGRectGetMaxY(inRect)); | |
CGPoint endPoint = CGPointMake(CGRectGetMinX(inRect), CGRectGetMinY(inRect)); | |
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); | |
CGShadingRef shading = CGShadingCreateAxial( | |
colorspace, endPoint, startPoint, gradientFunction, FALSE, FALSE); | |
CGContextSaveGState(context); | |
CGContextClipToRect(context, inRect); | |
CGContextDrawShading(context, shading); | |
CGContextRestoreGState(context); | |
CGShadingRelease(shading); | |
CGColorSpaceRelease(colorspace); | |
CGFunctionRelease(gradientFunction); | |
} | |
@implementation GlossGradientButton | |
@synthesize buttonColor = buttonColor_; | |
- (id)initWithFrame:(CGRect)frame color:(UIColor *)color { | |
if (self = [super initWithFrame:frame]) { | |
buttonColor_ = color; | |
} | |
return self; | |
} | |
- (void)drawRect:(CGRect)rect { | |
UIBezierPath *roundRectPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds | |
cornerRadius:5]; | |
CGContextRef context = UIGraphicsGetCurrentContext(); | |
CGContextSaveGState(context); | |
[roundRectPath addClip]; | |
DrawGlossGradient(context, self.buttonColor, self.bounds); | |
if (self.isHighlighted) { | |
[[UIColor colorWithRed:0.0 green:0.15 blue:0.35 alpha:0.5] setFill]; | |
[roundRectPath fill]; | |
} | |
CGContextRestoreGState(context); | |
[[UIColor colorWithWhite:1.0 alpha:0.234] setStroke]; | |
[roundRectPath setLineWidth:0.5]; | |
[roundRectPath stroke]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment