Анимация CAShapeLayer не остается на экране, а исчезает

Я пытаюсь нарисовать анимированный круг, но каждый сегмент должен иметь другой цвет. Теперь все работает, за исключением того, что моя часть, нарисованная перед повторным вызовом метода, исчезает, поэтому остается только последняя часть. Я не хочу этого, я хочу, чтобы после 4 раз весь круг рисовался разноцветными штрихами.

Как я могу исправить это, чтобы оно не исчезало?

Это мой код инициализации:

- (void)_initCircle {
    _circle = [CAShapeLayer layer];
    _radius = 100;

    // Make a circular shape
    _circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0 * _radius, 2.0 * _radius) cornerRadius:_radius].CGPath;

    // Center the shape in self.view
    _circle.position = CGPointMake(CGRectGetMidX(self.view.frame) - _radius,
                                   CGRectGetMidY(self.view.frame) - _radius);

    _circle.fillColor = [UIColor clearColor].CGColor;
    _circle.lineWidth = 5;

    // Add to parent layer
    [self.view.layer addSublayer:_circle];
}

Это моя ничья:

- (void)_drawStrokeOnCircleFrom:(float)start to:(float)end withColor:(UIColor *)color {
    // Configure the apperence of the circle
    _circle.strokeColor = color.CGColor;
    _circle.strokeStart = start;
    _circle.strokeEnd = end;

       [CATransaction begin];

    // Configure animation
    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration            = 2.0; // "animate over 10 seconds or so.."
    drawAnimation.repeatCount         = 1.0;  // Animate only once..

    // Animate from no part of the stroke being drawn to the entire stroke being drawn
    drawAnimation.fromValue = [NSNumber numberWithFloat:start];
    drawAnimation.toValue   = [NSNumber numberWithFloat:end];

    // Experiment with timing to get the appearence to look the way you want
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

    [CATransaction setCompletionBlock:^{
        NSLog(@"Complete animation");
        _index++;
        if(_index < _votes.count){
        _startStroke = _endStroke;
        _endStroke += [_votes[_index] floatValue] / _totalListens;
        [self _drawStrokeOnCircleFrom:_startStroke to:_endStroke withColor:_colors[_index]];
        }

    }];

    // Add the animation to the circle
    [_circle addAnimation:drawAnimation forKey:@"drawCircleAnimation"];

       [CATransaction commit];
}

3 ответа

Решение

Я решил проблему с дополнительными слоями следующим образом:

- (void)_drawStrokeOnCircle {

    [self _initCircle];

    [CATransaction begin];

    for (NSUInteger i = 0; i < 4; i++)
    {
        CAShapeLayer* strokePart = [[CAShapeLayer alloc] init];
        strokePart.fillColor = [[UIColor clearColor] CGColor];
        strokePart.frame = _circle.bounds;
        strokePart.path = _circle.path;
        strokePart.lineCap = _circle.lineCap;
        strokePart.lineWidth = _circle.lineWidth;


        // Configure the apperence of the circle
        strokePart.strokeColor = ((UIColor *)_colors[i]).CGColor;
        strokePart.strokeStart = [_segmentsStart[i] floatValue];
        strokePart.strokeEnd = [_segmentsEnd[i] floatValue];

        [_circle addSublayer: strokePart];

        // Configure animation
        CAKeyframeAnimation* drawAnimation = [CAKeyframeAnimation animationWithKeyPath: @"strokeEnd"];
        drawAnimation.duration            = 4.0;

        // Animate from no part of the stroke being drawn to the entire stroke being drawn
        NSArray* times = @[ @(0.0),
                            @(strokePart.strokeStart),
                            @(strokePart.strokeEnd),
                            @(1.0) ];
        NSArray* values = @[ @(strokePart.strokeStart),
                             @(strokePart.strokeStart),
                             @(strokePart.strokeEnd),
                             @(strokePart.strokeEnd) ];

        drawAnimation.keyTimes = times;
        drawAnimation.values = values;
        drawAnimation.removedOnCompletion = NO;
        drawAnimation.fillMode = kCAFillModeForwards;

        // Experiment with timing to get the appearence to look the way you want
        drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];


        [strokePart addAnimation: drawAnimation forKey: @"drawCircleAnimation"];
    }
    [CATransaction commit];
}

- (void)_initCircle {
    [_circle removeFromSuperlayer];
    _circle = [CAShapeLayer layer];
    _radius = 100;

    // Make a circular shape
    _circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0 * _radius, 2.0 * _radius) cornerRadius:_radius].CGPath;

    // Center the shape in self.view
    _circle.position = CGPointMake(CGRectGetMidX(self.view.frame) - _radius,
                                   CGRectGetMidY(self.view.frame) - _radius);

    _circle.fillColor = [UIColor clearColor].CGColor;
    _circle.lineWidth = 5;

    // Add to parent layer
    [self.view.layer addSublayer:_circle];
}

Попробуйте установить эти значения в вашей CABasicAnimation:

drawAnimation.removedOnCompletion = NO;
drawAnimation.fillMode = kCAFillModeForwards;

Это сработало для меня, используя "kCAFillModeBoth", оба утверждения необходимы:

//to keep it after finished
animation.removedOnCompletion = false;
animation.fillMode = kCAFillModeBoth;

SWIFT 4, Xcode 11:

let strokeIt = CABasicAnimation(keyPath: "strokeEnd")
let timeLeftShapeLayer = CAShapeLayer()

и в твоем viewDidLoad

  override func viewDidLoad() {
    super.viewDidLoad()
    drawTimeLeftShape()
    strokeIt.fillMode = CAMediaTimingFillMode.forwards
    strokeIt.isRemovedOnCompletion = false
    strokeIt.fromValue = 0
    strokeIt.toValue = 1
    strokeIt.duration = 2
    timeLeftShapeLayer.add(strokeIt, forKey: nil)
  }

и по UIBezierPathсоздать функцию для рисования круга:

func drawTimeLeftShape() {
        timeLeftShapeLayer.path = UIBezierPath(
            arcCenter: CGPoint(x: myView.frame.midX , y: myView.frame.midY),
            radius: myView.frame.width / 2,
            startAngle: -90.degreesToRadians,
            endAngle: 270.degreesToRadians,
            clockwise: true
        ).cgPath
        timeLeftShapeLayer.strokeColor = UIColor.red.cgColor
        timeLeftShapeLayer.fillColor = UIColor.clear.cgColor
        timeLeftShapeLayer.lineWidth = 1
        timeLeftShapeLayer.strokeEnd = 0.0
        view.layer.addSublayer(timeLeftShapeLayer)
    }
Другие вопросы по тегам