重叠装载机圈

我试图重现Apple为应用程序“Activity”制作的重叠圆圈。 (见下图)。

在此处输入图像描述

如果使用标准贝塞尔曲线路径,则启动/结束位置仅在0到2PI之间有效。 例如,如果尝试填充4PI(即使使用某些阴影),则无法模拟重叠加载。

如何制作类似于Apple解决方案的东西来创建重叠的圆圈?

这显示了一般的想法 – 变换绝对是要走的路。 您需要根据需要resize,箭头和阴影。 但是视图允许从Interface Builder调整色调和角度。 这应该让你去。

在此处输入图像描述

#import  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 

顺便说一下,我有点欺骗并使用了PaintCode。

这是我的尝试:

在此处输入图像描述

它完全是在代码中生成的(我必须使用Angle Gradient Layer来获取渐变,但其余的代码是我的)。 我可以通过应用旋转变换轻松获得任何所需的角度:

在此处输入图像描述

当然我也对所有值进行了硬编码,因为我只是尝试了它,但随意玩它:

 let con = UIGraphicsGetCurrentContext() let c1 = UIColor(red: 0.8, green: 0.8, blue: 0.7, alpha: 1).CGColor let c2 = UIColor(red: 0.8, green: 0.8, blue: 0.1, alpha: 1).CGColor let outer:CGFloat = 20 let diff:CGFloat = 20 let inner:CGFloat = outer + diff func circle(inset:CGFloat) { CGContextAddEllipseInRect(con, rect.rectByInsetting( dx: inset, dy: inset)) } CGContextSaveGState(con) circle(outer); circle(inner); CGContextEOClip(con) let im = AngleGradientLayer.newImageGradientInRect( rect, colors:[c1,c2], locations:[0,1]).takeRetainedValue() CGContextDrawImage(con, rect, im) CGContextRestoreGState(con) circle(outer) CGContextStrokePath(con) circle(inner) CGContextStrokePath(con) let (_,lower) = rect.rectsByDividing(rect.height / 2, fromEdge: .MinYEdge) CGContextAddRect(con, lower) CGContextEOClip(con) CGContextSetFillColorWithColor(con, c1) CGContextSaveGState(con) CGContextSetShadowWithColor(con, CGSizeMake(0,3), 6, UIColor.blackColor().colorWithAlphaComponent(0.7).CGColor) let top = lower.origin.y - diff/2 let left = rect.width - diff * 2 circle(outer); circle(inner); CGContextEOClip(con) CGContextFillEllipseInRect(con, CGRectMake(left,top,diff,diff)) CGContextRestoreGState(con) CGContextStrokeEllipseInRect(con, CGRectMake(left,top,diff,diff))