Horizontally animate progressbar created with drawRect - ios

So I've built out the progress bar in draw rect, and would like to animate it to move right horizontally as the progress changes, but am lost on what to do next.. If someone could point me in the right direction on how to go about this I would greatly appreciate it... thanks! Below is my code that I've got right now that's creating the drawrect.
ProgressBar - Made with DrawRect
- (void)drawRect:(CGRect)rect {
//// General Declarations
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
//// Color Declarations
UIColor* main_color_1 = [UIColor colorWithRed: 0.29 green: 0.357 blue: 0.133 alpha: 1];
UIColor* main_color_2 = [UIColor colorWithRed: 0.341 green: 0.412 blue: 0.153 alpha: 1];
UIColor* main_color_3 = [UIColor colorWithRed: 0.424 green: 0.498 blue: 0.243 alpha: 1];
UIColor* main_color_4 = [UIColor colorWithRed: 0.514 green: 0.592 blue: 0.337 alpha: 1];
UIColor* main_color_5 = [UIColor colorWithRed: 0.482 green: 0.561 blue: 0.306 alpha: 1];
UIColor* back_rect_1 = [UIColor colorWithRed: 0.145 green: 0.141 blue: 0.141 alpha: 1];
UIColor* back_rect_2 = [UIColor colorWithRed: 0.333 green: 0.333 blue: 0.333 alpha: 1];
UIColor* back_rect_3 = [UIColor colorWithRed: 0.416 green: 0.416 blue: 0.416 alpha: 1];
UIColor* back_rect_4 = [UIColor colorWithRed: 0.439 green: 0.439 blue: 0.439 alpha: 1];
UIColor* bacK_rect_shadow = [UIColor colorWithRed: 0.145 green: 0.145 blue: 0.145 alpha: 1];
//// Gradient Declarations
NSArray* main_gradientColors = [NSArray arrayWithObjects:
(id)main_color_1.CGColor,
(id)main_color_2.CGColor,
(id)main_color_3.CGColor,
(id)main_color_4.CGColor,
(id)main_color_5.CGColor, nil];
CGFloat main_gradientLocations[] = {0, 0.15, 0.43, 0.78, 1};
CGGradientRef main_gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)main_gradientColors, main_gradientLocations);
NSArray* back_rect_gradientColors = [NSArray arrayWithObjects:
(id)back_rect_1.CGColor,
(id)back_rect_2.CGColor,
(id)back_rect_3.CGColor,
(id)back_rect_4.CGColor, nil];
CGFloat back_rect_gradientLocations[] = {0, 0.35, 0.91, 1};
CGGradientRef back_rect_gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)back_rect_gradientColors, back_rect_gradientLocations);
//// Shadow Declarations
UIColor* shadow = bacK_rect_shadow;
CGSize shadowOffset = CGSizeMake(0.1, 1.1);
CGFloat shadowBlurRadius = 12;
//// back_rect Drawing
UIBezierPath* back_rectPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0, self.w, 26.5)];
CGContextSaveGState(context);
[back_rectPath addClip];
CGContextDrawLinearGradient(context, back_rect_gradient, CGPointMake(148.5, 0), CGPointMake(148.5, 26.5), 0);
CGContextRestoreGState(context);
////// back_rect Inner Shadow
CGRect back_rectBorderRect = CGRectInset([back_rectPath bounds], -shadowBlurRadius, -shadowBlurRadius);
back_rectBorderRect = CGRectOffset(back_rectBorderRect, -shadowOffset.width, -shadowOffset.height);
back_rectBorderRect = CGRectInset(CGRectUnion(back_rectBorderRect, [back_rectPath bounds]), -1, -1);
UIBezierPath* back_rectNegativePath = [UIBezierPath bezierPathWithRect: back_rectBorderRect];
[back_rectNegativePath appendPath: back_rectPath];
back_rectNegativePath.usesEvenOddFillRule = YES;
CGContextSaveGState(context);
{
CGFloat xOffset = shadowOffset.width + round(back_rectBorderRect.size.width);
CGFloat yOffset = shadowOffset.height;
CGContextSetShadowWithColor(context,
CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),
shadowBlurRadius,
shadow.CGColor);
[back_rectPath addClip];
CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(back_rectBorderRect.size.width), 0);
[back_rectNegativePath applyTransform: transform];
[[UIColor grayColor] setFill];
[back_rectNegativePath fill];
}
CGContextRestoreGState(context);
//// main_rect Drawing
UIBezierPath* main_rectPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0.1, progress, 26.5)];
CGContextSaveGState(context);
[main_rectPath addClip];
CGContextDrawLinearGradient(context, main_gradient, CGPointMake(116, 0), CGPointMake(116, 26.5), 0);
CGContextRestoreGState(context);
//// Cleanup
CGGradientRelease(main_gradient);
CGGradientRelease(back_rect_gradient);
CGColorSpaceRelease(colorSpace);
}

The way to animate a view using a UIView animation or a function like UIProgressView...
- (void)setProgress:(float)progress animated:(BOOL)animated;
is to draw the control on a CALayer using a path. You can then animate the percentage of the path that gets drawn and it will animate the view.
Other than that you could use UIImageViews and change the frames of them where the frame width relates to the progress. etc...
In the end I gave up trying to animate the progress with my OJFSegmentedProgressView.
However, if you set the progress often enough (i.e. every time something happens set the progress) then you wouldn't need to animate it as it would jump in small increments.

Related

How to Convert CAShapeLayer to CAGradientLayer?

my code of making CAShapeLayer is
UIBezierPath *circle = [UIBezierPath bezierPathWithArcCenter:CGPointMake(75, 125)
radius:50
startAngle:0
endAngle:1.8 * M_PI
clockwise:YES];
CAShapeLayer *circleLayer = [CAShapeLayer layer];
[circleLayer setFrame:CGRectMake(200 - 50, 300 - 50, 100, 100)];
circleLayer.path = circle.CGPath;
circleLayer.bounds = CGPathGetBoundingBox(circle.CGPath);
circleLayer.strokeColor = [UIColor colorWithRed:0.4 green:1.0 blue:0.2 alpha:0.5].CGColor;
[circleLayer setFillColor:[UIColor clearColor].CGColor];
circleLayer.lineWidth = 3.0;
if ([circleLayer animationForKey:#"SpinAnimation"] == nil) {
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat: 2 * M_PI];
animation.duration = 2.0f;
animation.repeatCount = INFINITY;
animation.removedOnCompletion = NO;
[circleLayer addAnimation:animation forKey:#"SpinAnimation"];
}
[self.view.layer addSublayer:circleLayer];
I want to make CAGradientLayer instead of CAShapeLayer.
REASON: I need to use gradient color in layer, which is not possible in CAShapeLayer.
I want to use yellow to black gradient upon Cirle.
Image :
In my required output, color is fetched from background image, and put some black at the end, or opacity 0 within layer.
Any Idea, suggestion.
Thanks.
One quick and dirty trick is adding a gradient layer as a sublayer then put some more layers with the background colors same as the superview (in the original question, it's white).
For example:
Add a gradient layer (and set proper cornerRadius).
Add a smaller layer with white background color at the center of the gradient layer (this will create a ring).
Create a small segment of arc with white background color.
However, this may not be suitable views with background images.
To solve this, you can create a custom subclass of UIView and override the drawRect method.
Suppose there are instance variables: startColor, endColor, radius, strokeWidth, and mirrored.
The variable mirrored is used to control the position of the gap (cut off left side or right side) and the rotation direction of the animation (clockwise or counter-clockwise).
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
CGFloat gradientColors[4 * 2];
extractColorComponents(_startColor, gradientColors, 0);
extractColorComponents(_endColor, gradientColors, 4);
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, gradientColors, NULL, 2);
CGColorSpaceRelease(baseSpace);
baseSpace = nil;
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient);
gradient = nil;
// fill 'clear' color
CGContextSetFillColorWithColor(ctx, [UIColor clearColor].CGColor);
CGContextSetStrokeColorWithColor(ctx, [UIColor clearColor].CGColor);
CGContextSetBlendMode(ctx, kCGBlendModeClear);
CGFloat innerCircleRadius = _radius - _strokeWidth;
// fill an 'empty' hole inside the gradient part
CGContextFillEllipseInRect(ctx, (CGRect){
{_strokeWidth, _strokeWidth},
{innerCircleRadius * 2, innerCircleRadius * 2}
});
// fill an 'empty' segment of arc
CGFloat startAngle = _mirrored ? (0.9 * M_PI) : (-0.1 * M_PI);
CGFloat endAngle = startAngle + 0.2 * M_PI;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:(CGPoint){_radius, _radius}
radius:_radius - _strokeWidth * 0.5
startAngle:startAngle
endAngle:endAngle
clockwise:YES];
path.lineWidth = _strokeWidth;
CGContextAddPath(ctx, path.CGPath);
CGContextSetLineWidth(ctx, _strokeWidth + 2);
CGContextStrokePath(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
}
Here's the complete implementation of the view.
Final result:
Two rings:
You can add two rings in your viewDidLoad or somewhere else with the following code to achieve the desired effect:
- (void)viewDidLoad
{
[super viewDidLoad];
UIColor *startColor = [UIColor colorWithHue:0.02 saturation:0.74 brightness:0.91 alpha:1];
UIColor *endColor = [UIColor colorWithHue:0.57 saturation:0.76 brightness:0.86 alpha:1];
CGPoint center = CGPointMake(160, 200);
Spinner *outerSpinner = [[Spinner alloc] initWithCenter:center
radius:50
strokeWidth:3
startColor:startColor
endColor:endColor
mirrored:NO];
Spinner *innerSpinner = [[Spinner alloc] initWithCenter:center
radius:40
strokeWidth:3
startColor:startColor
endColor:endColor
mirrored:YES];
[self.view addSubview:outerSpinner];
[self.view addSubview:innerSpinner];
[outerSpinner startAnimating];
[innerSpinner startAnimating];
}
Result:
The mask property on CALayer uses the alpha component of the mask layer to determine what should be visible and not. Since both of your colors (black and white) are fully opaque (no transparency) the mask has no effect. To fix this you should change one of the colors to a clear color:
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor],
(id)[[UIColor clearColor] CGColor], nil];
EDIT
class Colors {
let colorTop = UIColor(red: 192.0/255.0, green: 38.0/255.0, blue: 42.0/255.0, alpha: 1.0).CGColor
let colorBottom = UIColor(red: 35.0/255.0, green: 2.0/255.0, blue: 2.0/255.0, alpha: 1.0).CGColor
let gl: CAGradientLayer
init() {
gl = CAGradientLayer()
gl.colors = [ colorTop, colorBottom]
gl.locations = [ 0.0, 1.0]
}
}

animate an UIView frame 0 to 360 degree as song progress bar

I am playing audio songs from internet , I want to show the song progress something like this-
please help me how to animate UIView frame from 0 to 360 degree in song time duration.
Here is some code for drawing the two circles shown. Note that you will have to draw in an active CGContext. If you have any questions don't hesitate to ask.
Objective-C:
float percentDone = 0.25 //set this from 0 to 1
CGSize imageSize = CGSizeMake(88, 88)
//// Color Declarations
UIColor* pieColor = [UIColor colorWithRed: 0 green: 0.245 blue: 1 alpha: 1];
UIColor* background = [UIColor colorWithRed: 0.645 green: 0.645 blue: 0.645 alpha: 1];
//// Background gray circle
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0, 0, imageSize.width, imageSize.height))];
[background setFill];
[ovalPath fill];
//// Foreground progress wedge
CGRect oval2Rect = CGRectMake(0.f, 0.f, imageSize.width, imageSize.height);
UIBezierPath* oval2Path = UIBezierPath.bezierPath;
[oval2Path addArcWithCenter: CGPointMake(CGRectGetMidX(oval2Rect), CGRectGetMidY(oval2Rect)) radius: CGRectGetWidth(oval2Rect) / 2 startAngle: 270 * M_PI/180 endAngle: endAngle clockwise: YES];
[oval2Path addLineToPoint: CGPointMake(CGRectGetMidX(oval2Rect), CGRectGetMidY(oval2Rect))];
[oval2Path closePath];
[pieColor setFill];
[oval2Path fill];
Swift:
var percentDone = 0.25 //set this from 0 to 1
var imageSize = CGSizeMake(88, 88)
let endAngle = -(360.0 * percentDone) * CGFloat(M_PI)/180
//// Color Declarations
let pieColor = UIColor(red: 0.000, green: 0.245, blue: 1.000, alpha: 1.000)
let background = UIColor(red: 0.645, green: 0.645, blue: 0.645, alpha: 1.000)
//// Background gray circle
var ovalPath = UIBezierPath(ovalInRect: CGRectMake(0, 0, imageSize.width, imageSize.height))
background.setFill()
ovalPath.fill()
//// Foreground progress wedge
var oval2Rect = CGRectMake(0, 0, imageSize.width, imageSize.height)
var oval2Path = UIBezierPath()
oval2Path.addArcWithCenter(CGPointMake(oval2Rect.midX, oval2Rect.midY), radius: oval2Rect.width / 2, startAngle: 270 * CGFloat(M_PI)/180, endAngle: endAngle, clockwise: true)
oval2Path.addLineToPoint(CGPointMake(oval2Rect.midX, oval2Rect.midY))
oval2Path.closePath()
pieColor.setFill()
oval2Path.fill()
I done it my self as was looking for, i would like to share my answer step by step - First of all I created a custom UIView class CircleView -
CircleView.h
#import <UIKit/UIKit.h>
#interface CircleView : UIView
{
CGFloat startAngle;
CGFloat endAngle;
}
#property (nonatomic,assign) float percent;
#end
CircleView.m
#import "CircleView.h"
#implementation CircleView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
self.backgroundColor = [UIColor clearColor];
// Determine our start and stop angles for the arc (in radians)
startAngle = M_PI * 1.5;
endAngle = startAngle - (M_PI * 2);
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, self.center.x, self.center.y);
CGContextAddArc(context, self.center.x, self.center.y, rect.size.height/2, 360 , 0, 1);
CGContextSetRGBFillColor(context, 16.0/255.0f, 132.0/255.0f, 254.0/255.0f, 1.0f);
CGContextDrawPath(context, kCGPathFill);
CGContextSetRGBFillColor(context, 223.0f/255.0f, 224.0f/255.0f, 225.0/255.0, 1.0);
CGContextMoveToPoint(context, self.center.x, self.center.y);
CGContextAddArc(context, self.center.x, self.center.y, rect.size.height/2, startAngle , (endAngle - startAngle) * (_percent / 100.0) + startAngle, 1);
CGContextDrawPath(context, kCGPathFill);
}
#end
Now I used my custom class in cell something like this -
-(void)ReDrawCirculerView:(UIView *)viewHoldingCirculerView
{
[circleView removeFromSuperview];
circleView = [[CircleView alloc] initWithFrame:viewHoldingCirculerView.bounds];
circleView.percent=100.0;
[viewHoldingCirculerView addSubview:circleView];
[self.m_timer invalidate];
self.m_timer = nil;
NSTimeInterval playedTime = yourplayedtimeduration;
NSTimeInterval totaltime = totaltimeduration;
if(playedTime>0 && totaltime>0 && totaltime>playedTime)
{
float percentageplayed = playedTime*100/totaltime ;
circleView.percent= 100-percentageplayed;
}
self.m_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(ProgressSpin:) userInfo:nil repeats:YES];
}
- (void)ProgressSpin:(NSTimer *)timer
{
NSTimeInterval interval = 0.0;
NSTimeInterval playedTime = yoursonplayedduration;
NSTimeInterval totaltime = totalsonduration;
if(playedTime>0 && totaltime>0 && totaltime>playedTime)
{
interval =(totaltime-playedTime);
}
else
{ NSLog(#"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$%f====%f",circleView.percent,interval);
return;
}
// If we can decrement our percentage, do so, and redraw the view
if (circleView.percent > 0 )
{
if(isinf(circleView.percent/interval))
{
return;
}
circleView.percent = circleView.percent - circleView.percent/interval;
self.previousTimeInterval = interval;
[circleView setNeedsDisplay];
}
else
{
[self.m_timer invalidate];
self.m_timer = nil;
}
}
Try this
self.imageview.transform = CGAffineTransformMakeRotation(M_PI_2);

UITabBarItem image created in code doesn’t appear

I create the following View in code, the idea is to use it as an image in UITableViewCell and UITabBarItem:
- (void)drawRect:(CGRect)rect
{
// Fill the background with white
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor * whiteColor = [UIColor colorWithRed:1.0
green:1.0
blue:1.0
alpha:1.0];
CGContextSetFillColorWithColor(context, whiteColor.CGColor);
CGContextFillRect(context, self.bounds);
//// Color Declarations
UIColor* fillColor = [UIColor colorWithRed: 1.0
green: 1.0
blue: 1.0
alpha: 1.0];
UIColor* strokeColor = [UIColor colorWithRed: 0.0
green: 0.0
blue: 0.0
alpha: 1.0];
//// Big Oval Drawing
CGRect bigOvalRect = CGRectMake(rect.origin.x+2,
rect.origin.y+5,
42.0,
42.0);
UIBezierPath* bigOvalPath = [UIBezierPath bezierPath];
[bigOvalPath addArcWithCenter: CGPointMake(CGRectGetMidX(bigOvalRect), CGRectGetMidY(bigOvalRect))
radius: CGRectGetWidth(bigOvalRect) / 2
startAngle: 40 * M_PI/180
endAngle: 320 * M_PI/180
clockwise: YES];
[fillColor setFill];
[bigOvalPath fill];
[strokeColor setStroke];
bigOvalPath.lineWidth = 1;
[bigOvalPath stroke];
}
To create an UIImage from this UIView I am using this code:
#import <QuartzCore/QuartzCore.h>
+ (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
Everything works as expected when I use it in my UITableViewCells but when I set it as the image of my UITabBarItem I only see a blue rectangle (iOS7):
MyIcon *icon = [[MyIcon alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 50.0)];
UIImage *tabImage =[self imageWithView:icon];
self.navigationController.tabBarItem.image = tabImage;
I guess it is something related with the alpha of the image but how can I fix it?
It wasn't a problem related to the size of the view but to its alpha.
I fixed it by setting the backgroundColor (was whiteColor) and the fillColor to:
[UIColor clearColor]
and by setting the view as opaque in the initWithFrame: method:
[self setOpaque = NO];

Animate position of inner shadow

I want to animate the position of an inner shadow on a bezier I created using PaintCode. The offset of the shadow will be animated, here's two examples:
How can I make this an animatable property so that I can animate the movement of the shadow? The generated code (pasted into drawRect) looks like this:
//// General Declarations
CGContextRef context = UIGraphicsGetCurrentContext();
//// Color Declarations
UIColor* fillColor = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 1];
UIColor* strokeColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0.508];
//// Shadow Declarations
UIColor* shadow = strokeColor;
CGSize shadowOffset = CGSizeMake(3.1, 3.1);
CGFloat shadowBlurRadius = 5;
//// Oval Drawing
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(31.5, 33.5, 26, 26)];
[fillColor setFill];
[ovalPath fill];
////// Oval Inner Shadow
CGRect ovalBorderRect = CGRectInset([ovalPath bounds], -shadowBlurRadius, -shadowBlurRadius);
ovalBorderRect = CGRectOffset(ovalBorderRect, -shadowOffset.width, -shadowOffset.height);
ovalBorderRect = CGRectInset(CGRectUnion(ovalBorderRect, [ovalPath bounds]), -1, -1);
UIBezierPath* ovalNegativePath = [UIBezierPath bezierPathWithRect: ovalBorderRect];
[ovalNegativePath appendPath: ovalPath];
ovalNegativePath.usesEvenOddFillRule = YES;
CGContextSaveGState(context);
{
CGFloat xOffset = shadowOffset.width + round(ovalBorderRect.size.width);
CGFloat yOffset = shadowOffset.height;
CGContextSetShadowWithColor(context,
CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),
shadowBlurRadius,
shadow.CGColor);
[ovalPath addClip];
CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(ovalBorderRect.size.width), 0);
[ovalNegativePath applyTransform: transform];
[[UIColor grayColor] setFill];
[ovalNegativePath fill];
}
CGContextRestoreGState(context);
[strokeColor setStroke];
ovalPath.lineWidth = 1;
[ovalPath stroke];

IOS 6 Custom UIView by paintcode

I am an IOS beginner.
I am trying to show a custom button with code generated by paintcode.
I drag a View on Storyboard then set this generic view class to my custom view "GreenButton". When I run the app, the button does not show up. I added NSLogs and could see the drawRect method worked successfully.
The code generated by paintcode seems to include everything to draw the button. I just use XCode to resize my view.
Do I need to implement initWithFrame method at all?
//
// GreenButton.m
// Test
//
// Created by Tim on 13.04.2013.
// Copyright (c) 2013 Tim. All rights reserved.
//
#import "GreenButton.h"
#implementation GreenButton
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// setup the initial properties of the view
}
return self;
}
#pragma mark - Touch event overrides
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
NSLog(#"drawRect enter");
//// General Declarations
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
//// Color Declarations
UIColor* strokeColor = [UIColor colorWithRed: 0.419 green: 0.434 blue: 0.455 alpha: 1];
UIColor* baseColor = [UIColor colorWithRed: 0.218 green: 0.24 blue: 0.268 alpha: 1];
CGFloat baseColorRGBA[4];
[baseColor getRed: &baseColorRGBA[0] green: &baseColorRGBA[1] blue: &baseColorRGBA[2] alpha: &baseColorRGBA[3]];
UIColor* upperColor = [UIColor colorWithRed: (baseColorRGBA[0] * 0.8 + 0.2) green: (baseColorRGBA[1] * 0.8 + 0.2) blue: (baseColorRGBA[2] * 0.8 + 0.2) alpha: (baseColorRGBA[3] * 0.8 + 0.2)];
UIColor* lowerColor = [UIColor colorWithRed: (baseColorRGBA[0] * 0.9) green: (baseColorRGBA[1] * 0.9) blue: (baseColorRGBA[2] * 0.9) alpha: (baseColorRGBA[3] * 0.9 + 0.1)];
UIColor* lightUpColor = [UIColor colorWithRed: (baseColorRGBA[0] * 0.5 + 0.5) green: (baseColorRGBA[1] * 0.5 + 0.5) blue: (baseColorRGBA[2] * 0.5 + 0.5) alpha: (baseColorRGBA[3] * 0.5 + 0.5)];
UIColor* lightDownColor = [UIColor colorWithRed: (baseColorRGBA[0] * 0.8) green: (baseColorRGBA[1] * 0.8) blue: (baseColorRGBA[2] * 0.8) alpha: (baseColorRGBA[3] * 0.8 + 0.2)];
//// Gradient Declarations
NSArray* buttonGradientColors = [NSArray arrayWithObjects:
(id)upperColor.CGColor,
(id)lowerColor.CGColor, nil];
CGFloat buttonGradientLocations[] = {0, 1};
CGGradientRef buttonGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)buttonGradientColors, buttonGradientLocations);
NSArray* overlayGradientColors = [NSArray arrayWithObjects:
(id)lightUpColor.CGColor,
(id)[UIColor clearColor].CGColor, nil];
CGFloat overlayGradientLocations[] = {0, 1};
CGGradientRef overlayGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)overlayGradientColors, overlayGradientLocations);
NSArray* gradientColors = [NSArray arrayWithObjects:
(id)lightUpColor.CGColor,
(id)lightDownColor.CGColor, nil];
CGFloat gradientLocations[] = {0, 1};
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations);
//// Shadow Declarations
UIColor* buttonShadow = [UIColor blackColor];
CGSize buttonShadowOffset = CGSizeMake(0.1, 1.1);
CGFloat buttonShadowBlurRadius = 2;
UIColor* textShadow = [UIColor blackColor];
CGSize textShadowOffset = CGSizeMake(0.1, -0.1);
CGFloat textShadowBlurRadius = 5;
//// Abstracted Attributes
NSString* textContent = #"Update";
//// Back Rectangle Drawing
UIBezierPath* backRectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(48, 53, 120, 23) cornerRadius: 4];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, buttonShadowOffset, buttonShadowBlurRadius, buttonShadow.CGColor);
CGContextBeginTransparencyLayer(context, NULL);
[backRectanglePath addClip];
CGContextDrawLinearGradient(context, gradient, CGPointMake(108, 53), CGPointMake(108, 76), 0);
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
//// Rounded Rectangle Drawing
UIBezierPath* roundedRectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(49, 54, 118, 21) cornerRadius: 3];
CGContextSaveGState(context);
[roundedRectanglePath addClip];
CGContextDrawLinearGradient(context, buttonGradient, CGPointMake(108, 54), CGPointMake(108, 75), 0);
CGContextRestoreGState(context);
//// Overlay Drawing
UIBezierPath* overlayPath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(48, 53, 120, 23) cornerRadius: 4];
CGContextSaveGState(context);
[overlayPath addClip];
CGContextDrawRadialGradient(context, overlayGradient,
CGPointMake(54.72, 38.09), 10,
CGPointMake(108, 11.46), 102.2,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(context);
//// Text Drawing
CGRect textRect = CGRectMake(55, 54, 104, 21);
UIBezierPath* textPath = [UIBezierPath bezierPathWithRect: textRect];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, textShadowOffset, textShadowBlurRadius, textShadow.CGColor);
CGContextBeginTransparencyLayer(context, NULL);
[textPath addClip];
CGContextDrawLinearGradient(context, buttonGradient, CGPointMake(107, 54), CGPointMake(107, 75), 0);
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
[strokeColor setStroke];
textPath.lineWidth = 1;
[textPath stroke];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, textShadowOffset, textShadowBlurRadius, textShadow.CGColor);
[[UIColor whiteColor] setFill];
[textContent drawInRect: textRect withFont: [UIFont boldSystemFontOfSize: [UIFont systemFontSize]] lineBreakMode: NSLineBreakByWordWrapping alignment: NSTextAlignmentCenter];
CGContextRestoreGState(context);
//// Cleanup
CGGradientRelease(buttonGradient);
CGGradientRelease(overlayGradient);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
NSLog(#"drawRect exit");
}
#end
You do not need to implement initWithFrame: when using a Storyboard.
In fact, the storyboard will use initWithCoder: so it won't even be called.
I tested your code, and it works fine, however, you are not drawing in the top left corner, but somewhere in the middle of the view, so be sure to make the view large enough if you want to see your button.
Preferably draw in the top left corner.

Resources