I was trying to reproduce the overlapping circle Apple made for the application "Activity". (See image below).
If you use standard Bezier Path the staring/ending position will have effects only between 0 and 2PI. If you try, for example, to fill for 4PI (even using some shadows) you cannot simulate an overlapping loading.
How is possible to make something similar to the Apple solution to create an overlapping circle?
This shows the general idea--transform is definitely the way to go. You'll have to adjust the sizes, arrows, and shadows for what you need. But the view allow the tint and angle to be adjusted from Interface Builder. This should get you going.
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface ActivityCircleView : UIView
@property (nonatomic) IBInspectable CGFloat angleOfRotationInDegrees;
@end
#import "ActivityCircleView.h"
@implementation ActivityCircleView
- (void)setAngleOfRotation:(CGFloat)angleOfRotationInDegrees {
_angleOfRotationInDegrees = angleOfRotationInDegrees;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[self drawActivityWithTintColor:self.tintColor angleOfRotationInDegrees:self.angleOfRotationInDegrees];
}
- (void)drawActivityWithTintColor: (UIColor*)tintColor angleOfRotationInDegrees: (CGFloat)angleOfRotationInDegrees
{
//// General Declarations
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
//// Color Declarations
CGFloat tintColorRGBA[4];
[tintColor getRed: &tintColorRGBA[0] green: &tintColorRGBA[1] blue: &tintColorRGBA[2] alpha: &tintColorRGBA[3]];
UIColor* brighter = [UIColor colorWithRed: (tintColorRGBA[0] * 0.5 + 0.5) green: (tintColorRGBA[1] * 0.5 + 0.5) blue: (tintColorRGBA[2] * 0.5 + 0.5) alpha: (tintColorRGBA[3] * 0.5 + 0.5)];
//// Gradient Declarations
CGFloat gradientLocations[] = {0, 0.73};
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)@[(id)tintColor.CGColor, (id)brighter.CGColor], gradientLocations);
//// Shadow Declarations
NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor: UIColor.blackColor];
[shadow setShadowOffset: CGSizeMake(0.1, 0.1)];
[shadow setShadowBlurRadius: 5];
//// Activity Circle
{
//// Circle With Overlapping Shadow
{
CGContextSaveGState(context);
CGContextTranslateCTM(context, 50, 50);
CGContextRotateCTM(context, -angleOfRotationInDegrees * M_PI / 180);
//// Left Half Circle Drawing
UIBezierPath* leftHalfCirclePath = UIBezierPath.bezierPath;
[leftHalfCirclePath moveToPoint: CGPointMake(0, -40)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, -20) controlPoint1: CGPointMake(0, -40) controlPoint2: CGPointMake(0, -31.68)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-7.44, -18.57) controlPoint1: CGPointMake(-2.63, -20) controlPoint2: CGPointMake(-5.14, -19.49)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-20, -0) controlPoint1: CGPointMake(-14.8, -15.62) controlPoint2: CGPointMake(-20, -8.42)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, 20) controlPoint1: CGPointMake(-20, 11.05) controlPoint2: CGPointMake(-11.05, 20)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, 40) controlPoint1: CGPointMake(0, 27.41) controlPoint2: CGPointMake(0, 34.35)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-40, -0) controlPoint1: CGPointMake(-22.09, 40) controlPoint2: CGPointMake(-40, 22.09)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(-24.08, -31.94) controlPoint1: CGPointMake(-40, -13.05) controlPoint2: CGPointMake(-33.75, -24.64)];
[leftHalfCirclePath addLineToPoint: CGPointMake(-23.84, -32.13)];
[leftHalfCirclePath addCurveToPoint: CGPointMake(0, -40) controlPoint1: CGPointMake(-17.18, -37.07) controlPoint2: CGPointMake(-8.93, -40)];
[leftHalfCirclePath addLineToPoint: CGPointMake(0, -40)];
[leftHalfCirclePath closePath];
[tintColor setFill];
[leftHalfCirclePath fill];
//// Circle With Shadow Drawing
UIBezierPath* circleWithShadowPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(-10, 20, 20, 20)];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, shadow.shadowOffset, shadow.shadowBlurRadius, [shadow.shadowColor CGColor]);
[brighter setFill];
[circleWithShadowPath fill];
CGContextRestoreGState(context);
//// Right Half Circle Drawing
UIBezierPath* rightHalfCirclePath = UIBezierPath.bezierPath;
[rightHalfCirclePath moveToPoint: CGPointMake(40, -0)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, 40) controlPoint1: CGPointMake(40, 22.09) controlPoint2: CGPointMake(22.09, 40)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, 20) controlPoint1: CGPointMake(0, 33.83) controlPoint2: CGPointMake(0, 27.02)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(20, -0) controlPoint1: CGPointMake(11.05, 20) controlPoint2: CGPointMake(20, 11.05)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, -20) controlPoint1: CGPointMake(20, -11.05) controlPoint2: CGPointMake(11.05, -20)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(0, -40) controlPoint1: CGPointMake(0, -28.3) controlPoint2: CGPointMake(0, -35.35)];
[rightHalfCirclePath addCurveToPoint: CGPointMake(40, -0) controlPoint1: CGPointMake(22.09, -40) controlPoint2: CGPointMake(40, -22.09)];
[rightHalfCirclePath closePath];
CGContextSaveGState(context);
[rightHalfCirclePath addClip];
CGContextDrawLinearGradient(context, gradient, CGPointMake(20, -40), CGPointMake(20, 40), 0);
CGContextRestoreGState(context);
CGContextRestoreGState(context);
}
//// Arrow
{
//// Arrow Line Drawing
UIBezierPath* arrowLinePath = UIBezierPath.bezierPath;
[arrowLinePath moveToPoint: CGPointMake(43.5, 20.5)];
[arrowLinePath addLineToPoint: CGPointMake(57.5, 20.5)];
arrowLinePath.lineCapStyle = kCGLineCapRound;
[UIColor.blackColor setStroke];
arrowLinePath.lineWidth = 4;
[arrowLinePath stroke];
//// Arrow Head Drawing
UIBezierPath* arrowHeadPath = UIBezierPath.bezierPath;
[arrowHeadPath moveToPoint: CGPointMake(50.8, 14.5)];
[arrowHeadPath addLineToPoint: CGPointMake(57.5, 20.5)];
[arrowHeadPath addLineToPoint: CGPointMake(50.8, 26.5)];
arrowHeadPath.lineCapStyle = kCGLineCapRound;
[UIColor.blackColor setStroke];
arrowHeadPath.lineWidth = 4;
[arrowHeadPath stroke];
}
}
//// Cleanup
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
@end
By the way, I cheated a bit and used PaintCode.