如何将 CAShapeLayer 转换为 CAGradientLayer?

How to Convert CAShapeLayer to CAGradientLayer?

我制作 CAShapeLayer 的代码是

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

我想制作 CAGradientLayer 而不是 CAShapeLayer。

原因:我需要在层中使用渐变颜色,这在 CAShapeLayer 中是不可能的。

我想在 Cirle 上使用黄色到黑色的渐变。

图片:

在我要求的输出中,颜色是从背景图像中提取的,并在末尾放一些黑色,或者在图层中放上不透明度 0。

任何想法,建议。

谢谢。

CALayer 上的遮罩 属性 使用遮罩层的 alpha 分量来确定哪些应该可见,哪些不可见。由于您的两种颜色(黑色和白色)都是完全不透明的(无透明度),因此蒙版无效。要解决此问题,您应该将其中一种颜色更改为清晰的颜色:

gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], 
                                            (id)[[UIColor clearColor] CGColor], nil];

编辑

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

一个快速而肮脏的技巧是添加一个渐变层作为子层,然后放置更多背景颜色与超级视图相同的层(在原始问题中,它是白色)。

例如:

  1. 添加渐变图层(并设置适当的cornerRadius)。

  1. 在渐变图层的中心添加一个白色背景颜色的较小图层(这将创建一个 )。

  1. 创建一小段白色背景的圆弧。

但是,这可能不适合带有背景图片的视图。 要解决这个问题,您可以创建 UIView 的自定义子类并覆盖 drawRect 方法。

假设有实例变量:startColorendColorradiusstrokeWidthmirrored

变量mirrored用于控制间隙的位置(切掉左侧或右侧)和动画的旋转方向(顺时针或逆时针)。

- (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);
}

这是视图的 complete implementation

最终结果:

两环:

您可以在 viewDidLoad 或其他地方添加两个环,使用以下代码来达到预期效果:

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

}

结果: