我试图重现Apple为应用程序制作的重叠圈"活动"。 (见下图)。
如果使用标准贝塞尔曲线路径,则启动/结束位置仅在0到2PI之间有效。例如,如果您尝试填充4PI(即使使用某些阴影),则无法模拟重叠加载。
如何制作与Apple解决方案类似的内容以创建重叠的圆圈?
答案 0 :(得分:4)
这显示了一般的想法 - 变换绝对是要走的路。您需要根据需要调整大小,箭头和阴影。但是视图允许从Interface Builder调整色调和角度。这应该让你去。
#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
顺便说一句,我有点欺骗并使用了PaintCode。
答案 1 :(得分:3)
这是我的尝试:
它完全由代码生成(我必须使用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))