Question

I am developing a custom circular progress bar using UIBezierPath. I want to change the progress based on randomly generated CGFloat values.

My progress bar looks like this:

enter image description here

I drew the progress bar using the following code:

 // Draw the arc with bezier path
    int radius = 100;

    CAShapeLayer *arc = [CAShapeLayer layer];
    arc.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 50) radius:radius startAngle:M_PI endAngle:M_PI/150 clockwise:YES].CGPath;
    arc.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
                                CGRectGetMidY(self.view.frame)-radius);
    arc.cornerRadius = 100.0;
    arc.fillColor = [UIColor clearColor].CGColor;
    arc.strokeColor = [UIColor purpleColor].CGColor;
    arc.lineWidth = 6;

    [self.view.layer addSublayer:arc];

    // Animation of the progress bar
    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration            = 5.0; // "animate over 10 seconds or so.."
    drawAnimation.repeatCount         = 1.0;  // Animate only once..
    drawAnimation.removedOnCompletion = YES;   // Remain stroked after the animation..
    drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    drawAnimation.toValue   = [NSNumber numberWithFloat:10.0f];
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [arc addAnimation:drawAnimation forKey:@"drawCircleAnimation"];

    // Gradient of progress bar
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.frame = self.view.frame;
    gradientLayer.colors = @[(__bridge id)[UIColor redColor].CGColor,(__bridge id)[UIColor yellowColor].CGColor,(__bridge id)[UIColor purpleColor].CGColor ];
    gradientLayer.startPoint = CGPointMake(0,0.1);
    gradientLayer.endPoint = CGPointMake(0.5,0.2);
    [self.view.layer addSublayer:gradientLayer];
    gradientLayer.mask = arc;

    refreshButton = [[UIButton alloc] initWithFrame:CGRectMake(50, 370, 50, 50)];
    [refreshButton addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventTouchUpInside];
    [refreshButton setBackgroundImage:[UIImage imageNamed:@"refresh.png"] forState:UIControlStateNormal];
    [self.view addSubview:refreshButton];

The UIButton with the green arrow generates randomly CGFloat values. So my question is how to reset the animation so that it stops at the corresponding position if it is between 0.0 and 1.0? I tried to insert the code for the animation inside the method of the button, but as a result the new arc was drawn on top of the existing one.

-(void)refresh:(id)sender{
    NSLog(@"Refresh action:");
    CGFloat randomValue = ( arc4random() % 256 / 256.0 );
    NSLog(@"%f", randomValue);

    valueLabel.text = @"";
    valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(150, 370, 100, 50)];
    valueLabel.text = [NSString stringWithFormat: @"%.6f", randomValue];
    [self.view addSubview:valueLabel];

    // Draw the arc with bezier path
    int radius = 100;

    CAShapeLayer *arc = [CAShapeLayer layer];
    arc.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 50) radius:radius startAngle:M_PI endAngle:M_PI/150 clockwise:YES].CGPath;
    arc.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
                               CGRectGetMidY(self.view.frame)-radius);
    arc.cornerRadius = 100.0;
    arc.fillColor = [UIColor clearColor].CGColor;
    arc.strokeColor = [UIColor purpleColor].CGColor;
    arc.lineWidth = 6;

    [self.view.layer addSublayer:arc];

    // Animation of the progress bar
    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration            = 5.0; // "animate over 10 seconds or so.."
    drawAnimation.repeatCount         = 1.0;  // Animate only once..
    drawAnimation.removedOnCompletion = YES;   // Remain stroked after the animation..
    drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    drawAnimation.toValue   = [NSNumber numberWithFloat:randomValue];
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [arc addAnimation:drawAnimation forKey:@"drawCircleAnimation"];


}

I have no clue how to re-draw the arc, so any help or idea would be greatly appreciated!

Thanks a lot.

Granit

Was it helpful?

Solution

Try re-using the sublayer or replacing it. Make arc a class variable. Then cycle through the sublayers, remove the old arc then remake it with your new random float percentage. Once arc is a class variable then you can either replace it and animate from zero or you can animate from it's current percent to a new percent.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top