How to Convert CAShapeLayer to CAGradientLayer? - ios

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]
}
}

Related

UIBezierPath with color gradient

I've got an question about UIBezierPath.
For example I've got this path:
Now I want to have a color gradient from white to red. From left to right.
Here is my code:
UIBezierPath *bezierPath;
bezierPath = [UIBezierPath bezierPathWithArcCenter:_center radius:_radius startAngle:((4 * angle)) endAngle:(((20) * angle)) clockwise:YES];
[bezierPath addLineToPoint:_center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:0/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
Can anyone help me?
Edit 1:
I have this color wheel:
UIBezierPath *bezierPath;
for ( int i = 0; i < 360; i++) {
bezierPath = [UIBezierPath bezierPathWithArcCenter:_center radius:_radius startAngle:((i * angle)) endAngle:(((i + 1) * angle)) clockwise:YES];
[bezierPath addLineToPoint:_center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:i/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
}
but I want this: (With the white Gradient)
Use CAGradientLayer and mask it using CAShapeLayer Something like this
- (void)addCircle{
CAShapeLayer *shapeLayer = [CAShapeLayer new];
shapeLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(10, 10, 100, 100), 4, 4)].CGPath;
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.contentsScale = [UIScreen mainScreen].scale;
shapeLayer.shouldRasterize = NO;
CAGradientLayer *_gradientLayer = [CAGradientLayer layer];
_gradientLayer.frame =self.view.bounds;
_gradientLayer.startPoint = CGPointMake(0.0, 1);
_gradientLayer.endPoint = CGPointMake(1, 0);
_gradientLayer.colors = #[(id)[UIColor blueColor].CGColor,(id)[UIColor redColor].CGColor];
//Add gradient layer to view
[self.view.layer addSublayer:_gradientLayer];
_gradientLayer.mask = shapeLayer;
}
Above method will add a triangle may be you need to change start and end points. Also you can change gradient values to whatever you need.
Apple Docs
CAGradientLayer Tutorial
Update After update its more clear that its not triangle you want, but what you need is possible with CAGradientLayer and CAShapeLayer, you need to follow same approach where you can add gradient with different colors and locations (stops)(if you are adding locations then make sure locations and colors are equal) and then mask it with CAShapeLayer which was circle.
you can give it a try :)
- (void)drawRect:(CGRect)rect
{
CGFloat arcStep = (M_PI *2) / 360; // M_PI*2 is equivalent of full cirle
BOOL clocklwise = NO;
CGFloat x = CGRectGetWidth(rect) / 2; // circle's center
CGFloat y = CGRectGetHeight(rect) / 2; // circle's center
CGFloat radius = MIN(x, y) / 2;
CGContextRef ctx = UIGraphicsGetCurrentContext();
// draw colorful circle
CGContextSetLineWidth(ctx, radius*2);
for (CGFloat i = 0; i < 360; i+=1)
{
UIColor* c = [UIColor colorWithHue:i/360 saturation:1. brightness:1. alpha:1];
CGContextSetStrokeColorWithColor(ctx, c.CGColor);
CGFloat startAngle = i * arcStep;
CGFloat endAngle = startAngle + arcStep + 0.02;
CGContextAddArc(ctx, x, y, radius, startAngle, endAngle, clocklwise);
CGContextStrokePath(ctx);
}
// drawing circles then, you might want few of them - smaller radius and less alpha with each step
UIColor* c = [[UIColor whiteColor] colorWithAlphaComponent: 0.03];
for (CGFloat fillRadius = radius/2; fillRadius > 0; fillRadius -= 1.f)
{
CGContextSetLineWidth(ctx, fillRadius*2);
CGContextSetStrokeColorWithColor(ctx, c.CGColor);
CGContextAddArc(ctx, x, y, fillRadius, 0, M_PI * 2, clocklwise);
CGContextStrokePath(ctx);
}
}
Another take on Oleg's answer regarding the saturation (white gradient) that I find more pleasing, and in Swift (3).
You can add steps to the gradient if you want a bigger white circle (ex a 2nd white step at 0.2)
import UIKit
class HSView: UIView {
override func draw(_ rect: CGRect) {
let arcStep = 2 * CGFloat.pi / 360
let isClockwise = false
let x = rect.width / 2
let y = rect.height / 2
let radius = min(x, y) / 2
let ctx = UIGraphicsGetCurrentContext()
ctx?.setLineWidth(2 * radius)
for i in 0..<360 {
let color = UIColor(hue: CGFloat(i)/360, saturation: 1, brightness: 1, alpha: 1)
let startAngle = CGFloat(i) * arcStep
let endAngle = startAngle + arcStep + 0.02
ctx?.setStrokeColor(color.cgColor)
ctx?.addArc(center: CGPoint(x: x, y: y), radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: isClockwise)
ctx?.strokePath()
}
let gradient = CGGradient(colorsSpace: UIColor.white.cgColor.colorSpace,
colors: [
UIColor.white.cgColor,
UIColor.white.withAlphaComponent(0).cgColor,
] as CFArray,
locations: [
0,
1,
]
)
ctx?.drawRadialGradient(gradient!, startCenter: CGPoint(x: x, y: y), startRadius: 0, endCenter: CGPoint(x: x, y: y), endRadius: 2 * radius, options: .drawsAfterEndLocation)
}
}
You can try this:
//// General Declarations
CGContextRef context = UIGraphicsGetCurrentContext();
//// Shadow Declarations
NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor: UIColor.whiteColor];
[shadow setShadowOffset: CGSizeMake(2.1, -4.1)];
[shadow setShadowBlurRadius: 5];
//// Bezier Drawing
UIBezierPath* bezierPath = UIBezierPath.bezierPath;
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 1;
[bezierPath stroke];
//// Bezier 2 Drawing
UIBezierPath* bezier2Path = UIBezierPath.bezierPath;
[bezier2Path moveToPoint: CGPointMake(170.5, 59.5)];
[bezier2Path addCurveToPoint: CGPointMake(170.5, 71.5) controlPoint1: CGPointMake(173.5, 65.5) controlPoint2: CGPointMake(170.5, 71.5)];
[bezier2Path addLineToPoint: CGPointMake(155.5, 57.5)];
[bezier2Path addLineToPoint: CGPointMake(170.5, 59.5)];
[UIColor.redColor setFill];
[bezier2Path fill];
////// Bezier 2 Inner Shadow
CGContextSaveGState(context);
UIRectClip(bezier2Path.bounds);
CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);
CGContextSetAlpha(context, CGColorGetAlpha([shadow.shadowColor CGColor]));
CGContextBeginTransparencyLayer(context, NULL);
{
UIColor* opaqueShadow = [shadow.shadowColor colorWithAlphaComponent: 1];
CGContextSetShadowWithColor(context, shadow.shadowOffset, shadow.shadowBlurRadius, [opaqueShadow CGColor]);
CGContextSetBlendMode(context, kCGBlendModeSourceOut);
CGContextBeginTransparencyLayer(context, NULL);
[opaqueShadow setFill];
[bezier2Path fill];
CGContextEndTransparencyLayer(context);
}
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
and the result will be:
You will archive it by using QuartsCore. If you want get image with your figure, you can call UIGraphicsBeginImageContext(), if you want draw it on UIView you should overload method - (void)drawRect:(CGRect)rect of UIView.
You can add path to context, and use it for clipping context (Don't forget save the context state before). After you can draw the gradient. The gradient will be clipped by path.
You will get something like this:
CGPathRef path = [bezierPath CGPath];
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextClip(context);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSArray *colors = [NSArray arrayWithObjects:(id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors( colorSpace, (CFArrayRef)colors, NULL);
CGColorSpaceRelease(colorSpace);
colorSpace = NULL;
CGContextDrawLinearGradient(context, gradient, CGPointMake(0.0, 0.0), CGPointMake(100.0, 100.0), kNilOptions);
CGContextRestoreGState(context);

How to draw the gradient in iOS

I want to draw the Circular progress view with gradient as image :
Design Image
I tried the below code but the result color is not correct. This is my code:
//draw gradient
CGFloat colors [] = {
1.0, 0.7,
0.2, 0.4
};
CGFloat locations[] = { 0.0, 1.0 };
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceGray(); // gray colors want gray color space
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, locations, 2);
CGColorSpaceRelease(baseSpace), baseSpace = NULL;
CGContextSaveGState(context);
CGContextAddPath(context, progressPath);
CGContextClip(context);
CGRect boundingBox = CGPathGetBoundingBox(progressPath);
CGPoint gradientStart = CGPointMake(0.0, CGRectGetMinY(boundingBox));
CGPoint gradientEnd = CGPointMake(1.0, CGRectGetMaxY(boundingBox));
CGContextDrawLinearGradient(context, gradient, gradientStart, gradientEnd, 0);
CGGradientRelease(gradient), gradient = NULL;
CGContextRestoreGState(context);
The progressPath is the progress line with color :
[UIColor colorWithRed:21/255.0f green:182/255.0f blue:217/255.0f alpha:1.0]
UPDATE:
This is an image my code produced: Result Image
The result image is not the same the design, the color is not the same. I dont know why.
Please help me to correct this. Thanks in advance.
The kind of gradient you are looking for, where the color varies as a function of the angle around a center point, is called an angle gradient. Unfortunately, iOS does not have a built-in way to draw angle gradients, but you can do it using an open-source library such as paiv/AngleGradientLayer.
Working code:
- (void) setGradientWithFrame:(CGRect)frame
{
//create the gradient
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = frame;
//this example is white-black gradient, change it to the color you want..
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor blackColor] CGColor], nil];
gradient.cornerRadius = frame.size.height/2.0f;
[self.view.layer insertSublayer:gradient atIndex:0];
CALayer *whiteCircle = [CALayer layer];
whiteCircle.frame = CGRectMake(frame.origin.x + 10, frame.origin.y + 10, frame.size.width - 20, frame.size.height - 20);
whiteCircle.backgroundColor = [[UIColor whiteColor] CGColor];
whiteCircle.cornerRadius = whiteCircle.frame.size.width/2.0f;
[self.view.layer insertSublayer:whiteCircle atIndex:1];
CALayer *whitesquare = [CALayer layer];
whitesquare.frame = CGRectMake(50, frame.size.height - 20, 25, 25);
whitesquare.backgroundColor = [[UIColor whiteColor] CGColor];
whitesquare.transform = CATransform3DMakeRotation(-20.0 / 180.0 * M_PI, 0.0, 0.0, 1.0);
[self.view.layer insertSublayer:whitesquare atIndex:2];
}
to call the method:
[self setGradientWithFrame:CGRectMake(0, 0, 100, 100)];
PS. change the color to the color of gradient to the color you want:

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];

Why isn't this random color method working?

I have a for loop inside the drawRect method that draws a number of circles to fill the screen. I'm trying to make it so each circle has a new random stroke. For some reason nothing is showing up. Here is my randomColor method:
-(UIColor *) randomColor
{
int red, green, blue, alpha;
red = arc4random_uniform(255);
green = arc4random_uniform(255);
blue = arc4random_uniform(255);
alpha = arc4random_uniform(255);
UIColor *colorToReturn = [[UIColor alloc] initWithRed:red green:green blue:blue alpha:alpha];
return colorToReturn;
}
and I try implementing it here:
-(void) drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
// Firgure out the center of the bounds rectangle
CGPoint center;
center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0;
// The radius of the circle should be nearly as big as the view
float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0;
// The thickness of the line should be 10 points wide
CGContextSetLineWidth(ctx, 10);
// The color of the line should be gray (red/green/blue = 0.6, alpha = 1.0)
// CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0);
// The same as
// [[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0] setStroke];
// The same as
// [[UIColor redColor] setStroke];
// Draw concentric circles from the outside in
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
// Add a path to the context
CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
[[self randomColor] setStroke];
// Perform drawing instructions; removes path
CGContextStrokePath(ctx);
}
UIColor takes a float between 0 and 1 as a value for its RGB components:
UIColor *colorToReturn = [[UIColor alloc] initWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:alpha];
I use the two macros below to get a random color. The first one is a straightforward macro that I often use while setting colors. The second one returns a random color using it:
#define _RGB(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]
#define kCLR_RANDOM_COLOR _RGB(arc4random()%255, arc4random()%255, arc4random()%255, 1)

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];

Resources