根据随机 CGFloat 值重新绘制 UIBezierPath

Posted

技术标签:

【中文标题】根据随机 CGFloat 值重新绘制 UIBezierPath【英文标题】:Re-draw UIBezierPath based on random CGFloat value 【发布时间】:2013-12-17 14:36:50 【问题描述】:

我正在使用UIBezierPath 开发一个自定义的圆形进度条。我想根据随机生成的 CGFloat 值更改进度。

我的进度条是这样的:

我使用以下代码绘制了进度条:

 // 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];

带有绿色箭头的 UIButton 会随机生成 CGFloat 值。所以我的问题是如何重置动画,使其在0.0和1.0之间停止在相应的位置?我试图在按钮的方法中插入动画代码,但结果是在现有弧的顶部绘制了新的弧。

-(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"];



我不知道如何重新绘制弧线,所以任何帮助或想法将不胜感激!

非常感谢。

花岗岩

【问题讨论】:

第一个建议:您的valueLabel 被吸引到了它的自我之上。尽量不要每次刷新都重新创建它,只需更改它的文本即可。其次,尝试重新使用子层或替换它。将arc 设为类变量。然后循环遍历子层,删除旧的arc,然后用新的随机浮动百分比重新制作它。一旦arc 是一个类变量,那么您可以替换它并从零开始动画,或者您可以从它的当前百分比动画到新百分比。 @Putz1103 我将 arc 设为类变量,我正在重绘圆,它正在工作。你能回答让我接受吗? :) 谢谢 【参考方案1】:

尝试重新使用子层或替换它。使 arc 成为类变量。然后循环遍历子层,删除旧弧,然后用新的随机浮动百分比重新制作。一旦 arc 是一个类变量,那么您可以替换它并从零开始动画,或者您可以从它的当前百分比动画到新的百分比。

【讨论】:

以上是关于根据随机 CGFloat 值重新绘制 UIBezierPath的主要内容,如果未能解决你的问题,请参考以下文章

R统计分布绘图

调用方式 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 无需重新加

加快从叠加截断正态分布中绘制随机值

计算每个更新的值及其对应的随机数,然后绘制它们

CAGradientLayer 不绘制表单遮罩

swift 3 中 swift 2 的 CGFloat.random(min: CGFloat, max: CGFloat) 是啥?