首页 > 解决方案 > 绘制或填充颜色时为 CAGradientLayer 设置动画

问题描述

我正在研究循环进度视图。我正在添加带有未选中和选中颜色的圆的切片或 ARC,这些颜色表示某些任务的进度。

我正在CALayers绘制弧线并添加动画。对于没有渐变的所有切片,一切正常。如果我在任何切片/弧中添加渐变,它在立即绘制时不会动画。

请帮助我在这个问题上添加CAShapeLayer动画CAGradientLayer

下面是我的代码和我尝试过的方法......

注意:我尝试了三种添加动画的方法。请同时检查注释代码

- (void)drawArcAnimation:(CGRect)rect {
if (self.itemIndex >= self.sliceItems.count) {
    return;
}
float total = [self calculateTotal];

SliceItem *item = self.sliceItems[self.itemIndex];

UIBezierPath* path = [UIBezierPath bezierPath];
float angle = (item.itemValue/total) * 2 * M_PI;
float endAngle = self.startAngle + angle;
totalProgress += item.itemValue;
if (item.shouldGradient) {

    // ***** This code will be used if we go for second approach of animation ****
    UIBezierPath *rectToAnimateFrom = [UIBezierPath bezierPathWithArcCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2) radius:rect.size.width/2 - self.lineWidth startAngle:self.startAngle endAngle:self.startAngle clockwise:NO];
    UIBezierPath *rectToAnimateTo = [UIBezierPath bezierPathWithArcCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2) radius:rect.size.width/2 - self.lineWidth startAngle:self.startAngle endAngle:endAngle clockwise:NO];
    // ***** END ****

    CGMutablePathRef arc = CGPathCreateMutable();
    CGPathAddArc(arc, NULL,
                 (rect.size.width / 2), (rect.size.height / 2),
                 rect.size.width/2 - self.lineWidth,
                 self.startAngle,
                 endAngle,
                 NO);
    self.startAngle = endAngle;

    CGFloat lineWidth = self.lineWidth;

    CGPathRef strokedArc =
    CGPathCreateCopyByStrokingPath(arc, NULL,
                                   lineWidth,
                                   kCGLineCapButt,
                                   kCGLineJoinMiter, // the default
                                   10); // 10 is default miter limit
    CAShapeLayer *segment = [CAShapeLayer layer];
    segment.fillColor = item.itemColor.CGColor;
    segment.strokeColor = [UIColor clearColor].CGColor;
    segment.path = strokedArc;
    //        [self.baseLayer addSublayer:segment];

    CAGradientLayer *gradient = [CAGradientLayer layer];

    if (totalProgress > 50) {
        gradient.colors = @[(id)item.itemSecondaryColor.CGColor, (id)item.itemColor.CGColor,(id)item.itemColor.CGColor,(id)item.itemColor.CGColor];
    }else {
        gradient.colors = @[(id)item.itemColor.CGColor, (id)item.itemColor.CGColor, (id)item.itemColor.CGColor,(id)item.itemSecondaryColor.CGColor];
    }
    gradient.frame = CGPathGetBoundingBox(segment.path);

    CAShapeLayer *mask = [CAShapeLayer layer];
    CGAffineTransform translation = CGAffineTransformMakeTranslation(-CGRectGetMinX(gradient.frame),
                                                                     -CGRectGetMinY(gradient.frame));
    mask.path = CGPathCreateCopyByTransformingPath(segment.path,
                                                   &translation);
    gradient.mask = mask;
    [self.baseLayer addSublayer:gradient];

    if (_duration == 0.0) {
        self.itemIndex++;
        [self drawArcAnimation:rect];
    }else {

        // ******* First Approach to animate *******

        [CATransaction begin];
        CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        drawAnimation.duration            = _duration*(angle/(2 * M_PI));
        drawAnimation.repeatCount         = 1.0;

        drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
        drawAnimation.toValue   = [NSNumber numberWithFloat:1.0f];

        drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        [CATransaction setCompletionBlock:^{
            self.itemIndex++;
            [self drawArcAnimation:rect];
        }];
        [gradient addAnimation:drawAnimation forKey:@"drawCircleAnimation"];
        [CATransaction commit];

        // ******* Second Approach to animate *******

//            [CATransaction begin];
//            CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
//            animation.fromValue = (__bridge id _Nullable)(rectToAnimateFrom.CGPath);
//            animation.toValue = (__bridge id _Nullable)(rectToAnimateTo.CGPath);
//            animation.duration = 3;
//            animation.repeatCount = 1;
//            animation.removedOnCompletion = false;
//            animation.fillMode = kCAFillModeForwards;
//            
//            [CATransaction setCompletionBlock:^{
//                self.itemIndex++;
//                [self drawArcAnimation:rect];
//            }];
//            
//            [gradient addAnimation:animation forKey:@"fill animation"];
//            [CATransaction commit];



        // ******* Third Approach to animate *******

//            NSArray *fromColors = @[(id)UIColor.whiteColor.CGColor, (id)UIColor.clearColor.CGColor];
//            NSArray *toColors = gradient.colors;
//            [gradient setColors:toColors];
//            
//            [CATransaction begin];
//            CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"colors"];
//            animation1.fromValue             = fromColors;
//            animation1.toValue               = toColors;
//            animation1.duration              = _duration;
//            animation1.removedOnCompletion   = YES;
//            animation1.fillMode              = kCAFillModeForwards;
//            animation1.timingFunction        = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
//            [CATransaction setCompletionBlock:^{
//                self.itemIndex++;
//                [self drawArcAnimation:rect];
//            }];
//            [gradient addAnimation:animation1 forKey:@"animateGradient"];
//            [CATransaction commit];

    }

}else {
    [path addArcWithCenter:CGPointMake(rect.size.width / 2, rect.size.height / 2)
                    radius:rect.size.width/2 - self.lineWidth
                startAngle:self.startAngle
                  endAngle:endAngle
                 clockwise:YES];
    self.startAngle = endAngle;

    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.path = path.CGPath;
    CGRect frame = path.bounds;
    frame.size.height = rect.size.height;
    frame.size.width = frame.size.width * 30;
    layer.strokeColor = item.itemColor.CGColor;

    layer.fillColor = nil;
    layer.lineWidth = self.lineWidth;
    layer.strokeStart = 0;
    layer.strokeEnd = 1.0;

    [self.baseLayer addSublayer:layer];

    if (_duration == 0.0) {
        self.itemIndex++;
        [self drawArcAnimation:rect];
    }else {
        [CATransaction begin];
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        animation.duration = _duration*(angle/(2 * M_PI));
        animation.fromValue = @(0.0);
        animation.toValue = @(1.0);
        [CATransaction setCompletionBlock:^{
            self.itemIndex++;
            [self drawArcAnimation:rect];
        }];
        [layer addAnimation:animation forKey:nil];
        [CATransaction commit];
    }
}
}

在上面的代码中,您可以使用条件if (item.shouldGradien)及其else部分。动画在其他部分工作正常,CALayers但在渐变部分没有。

我在这里做错了什么?任何帮助... ???

标签: iosobjective-ciphoneanimationcalayer

解决方案


推荐阅读