Why, when I set the low duration value for my CABasicAnimation, does it jump?

Project example: http://cl.ly/1W3V3b0D2001

I use CABasicAnimationto create a progress indicator that looks like a pie chart. Similar to iOS 7 app loading animation:

enter image description here

The animation is configured as follows:

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];

    CGFloat radius = CGRectGetWidth(self.frame) / 2;
    CGFloat inset  = 1;
    CAShapeLayer *ring = [CAShapeLayer layer];
    ring.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
                                           cornerRadius:radius-inset].CGPath;

    ring.fillColor = [UIColor clearColor].CGColor;
    ring.strokeColor = [UIColor whiteColor].CGColor;
    ring.lineWidth = 2;

    self.innerPie = [CAShapeLayer layer];
    inset = radius/2;
    self.innerPie.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
                                               cornerRadius:radius-inset].CGPath;
    self.innerPie.fillColor = [UIColor clearColor].CGColor;
    self.innerPie.strokeColor = [UIColor whiteColor].CGColor;
    self.innerPie.lineWidth = (radius-inset)*2;

    self.innerPie.strokeStart = 0;
    self.innerPie.strokeEnd = 0;

    [self.layer addSublayer:ring];
    [self.layer addSublayer:self.innerPie];

    self.progress = 0.0;
}

The animation starts by setting the viewing progress:

- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
    self.progress = progress;

    if (animated) {
        CGFloat totalDurationForFullCircleAnimation = 0.25;

        CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        self.innerPie.strokeEnd = progress;
        pathAnimation.delegate = self;
        pathAnimation.fromValue = @([self.innerPie.presentationLayer strokeEnd]);
        pathAnimation.toValue = @(progress);
        pathAnimation.duration = totalDurationForFullCircleAnimation * ([pathAnimation.toValue floatValue] - [pathAnimation.fromValue floatValue]);

        [self.innerPie addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
    }
    else {
        [CATransaction setDisableActions:YES];
        [CATransaction begin];
        self.innerPie.strokeEnd = progress;
        [CATransaction commit];
    }
}

However, in those cases when I set the progress to something small, for example 0.25, there was a transition to animation. He goes a little forward clockwise, bounces back, and then continues to move forward, as usual. It doesn’t cost anything to happen if the duration or progress is set higher.

? , , . ?

+4
3

! . if (animated):

self.innerPie.strokeEnd = progress;

innerPie Core Animation, ( ). . , strokeEnd:

[CATransaction begin];
[CATransaction setDisableActions:YES];
self.innerPie.strokeEnd = progress;
[CATransaction commit];

( , setDisableActions: /.)

, - setAnimationDuration:, .

:

, drawRect: , strokeEnd. , drawRect:. init didMoveToWindow: .

, progress [self.innerPie.presentationLayer strokeEnd] ; , , .

+4

drawRect:? drawRect:.

drawRect, self.layer. , .

- :

- (id)initWithFrame:(CGRect)frame
{
  if (!(self = [super initWithFrame:frame])
    return nil;

  CGFloat radius = CGRectGetWidth(self.frame) / 2;
  CGFloat inset  = 1;
  CAShapeLayer *ring = [CAShapeLayer layer];
  ring.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
                                        cornerRadius:radius-inset].CGPath;

  ring.fillColor = [UIColor clearColor].CGColor;
  ring.strokeColor = [UIColor whiteColor].CGColor;
  ring.lineWidth = 2;

  self.innerPie = [CAShapeLayer layer];
  inset = radius/2;
  self.innerPie.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
                                            cornerRadius:radius-inset].CGPath;
  self.innerPie.fillColor = [UIColor clearColor].CGColor;
  self.innerPie.strokeColor = [UIColor whiteColor].CGColor;
  self.innerPie.lineWidth = (radius-inset)*2;

  self.innerPie.strokeStart = 0;
  self.innerPie.strokeEnd = 0;

  [self.layer addSublayer:ring];
  [self.layer addSublayer:self.innerPie];

  self.progress = 0.0;

  return self;
}
+1

, , . , , .

0

Source: https://habr.com/ru/post/1532583/


All Articles