简体   繁体   English

怎么把CAShapeLayer转换成CAGradientLayer?

[英]How to Convert CAShapeLayer to CAGradientLayer?

my code of making CAShapeLayer is 我制作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];

I want to make CAGradientLayer instead of CAShapeLayer. 我要制作CAGradientLayer而不是CAShapeLayer。

REASON: I need to use gradient color in layer, which is not possible in CAShapeLayer. 原因:我需要在图层中使用渐变颜色,这在CAShapeLayer中是不可能的。

I want to use yellow to black gradient upon Cirle. 我想在Cirle上使用黄色到黑色的渐变。

Image : 图片 :

在此处输入图片说明

In my required output, color is fetched from background image, and put some black at the end, or opacity 0 within layer. 在我所需的输出中,从背景图像中提取颜色,并在其末尾添加一些黑色,或在图层内添加不透明度0。

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: 例如:

  1. Add a gradient layer (and set proper cornerRadius ). 添加一个渐变层(并设置适当的cornerRadius )。

填充渐变层

  1. Add a smaller layer with white background color at the center of the gradient layer (this will create a ring ). 在渐变层的中心添加一个具有白色背景色的较小层(这将创建一个ring )。

环

  1. 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. 为了解决这个问题,您可以创建UIView的自定义子类并重写drawRect方法。

Suppose there are instance variables: startColor , endColor , radius , strokeWidth , and mirrored . 假设有实例变量: startColorendColorradiusstrokeWidthmirrored

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

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: 您可以使用以下代码在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];

}

Result: 结果:

双动画环

The mask property on CALayer uses the alpha component of the mask layer to determine what should be visible and not. CALayer上的mask属性使用mask图层的alpha分量来确定哪些内容应该可见,哪些不可见。 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]
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM