我试图实现一个循环指标,当值发生变化时,它会用动画绘制自己。
我使用CAShapeLayer
绘制动画。到目前为止,我每次都从头开始绘制它,它按预期工作。现在我想让它更时尚,并将它向前拉,并且擦除"取决于新值是否大于或低于先前值。我不确定如何实现擦除部分。这是一个背景,所以我不能只用白色画在上面。这是一张图片,可以更好地了解它的外观。
有关如何实现擦除部分的任何想法?在类似的问题上有一些关于SO的解决方案,但那些不涉及动画。
我使用此代码绘制:
- (void)drawCircleAnimatedWithStartAngle:(CGFloat)startAngle
endAngle:(CGFloat)endAngle
color:(UIColor *)color
radius:(int)radius
lineWidth:(int)lineWidth {
CAShapeLayer *circle = [CAShapeLayer layer];
circle.name = @"circleLayer";
circle.path = ([UIBezierPath bezierPathWithArcCenter:CGPointMake(radius, radius) radius:radius-1 startAngle:startAngle endAngle:endAngle clockwise:YES].CGPath);
// Configure the apperence of the circle
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor colorWithRed:19.0/255 green:167.0/255 blue:191.0/255 alpha:1].CGColor;
circle.lineWidth = lineWidth;
// Add to parent layer
for (CALayer *layer in self.circleView.layer.sublayers) {
if ([layer.name isEqualToString:@"circleLayer"]) {
[layer removeFromSuperlayer];
break;
}
}
[self.circleView.layer addSublayer:circle];
circle.zPosition = 1;
// Configure animation
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
drawAnimation.duration = 0.5;
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:0.0f];
drawAnimation.toValue = [NSNumber numberWithFloat:1.0f];
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// Add the animation to the circle
[circle addAnimation:drawAnimation forKey:@"drawCircleAnimation"];
}
答案 0 :(得分:6)
我能够以与你正在做的事情略有不同的方式做到这一点。我没有绘制一定长度的弧线,而是让我的路径成了一个完整的圆圈,但只是将它放在一边。您会注意到我使用表示层的strokeEnd来获取toValue,因此如果在您需要更改最终strokeEnd的值时动画正在进行中,它将从当前绘制路径的位置开始。这是我的视图控制器中的代码;轮廓图层绘制灰色圆圈,类似于图像中的内容。我在我的视图中添加了5个按钮(用于测试),其标签用于更改动画的最终笔触值,
@implementation ViewController {
UIView *circleView;
RDShapeLayer *circle;
}
- (void)viewDidLoad {
[super viewDidLoad];
circleView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
CALayer *outlineLayer = [CALayer new];
outlineLayer.frame = circleView.bounds;
outlineLayer.borderWidth = 2;
outlineLayer.borderColor = [UIColor lightGrayColor].CGColor;
outlineLayer.cornerRadius = circleView.frame.size.width/2.0;
[circleView.layer addSublayer:outlineLayer];
[self.view addSubview:circleView];
circle = [[RDShapeLayer alloc] initWithFrame:circleView.bounds color:[UIColor blueColor].CGColor lineWidth:4];
[circleView.layer addSublayer:circle];
}
-(void)animateToPercentWayAround:(CGFloat) percent {
circle.strokeEnd = percent/100.0;
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
drawAnimation.duration = 1.0;
drawAnimation.fromValue = @([circle.presentationLayer strokeEnd]);
drawAnimation.toValue = @(percent/100.0);
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[circle addAnimation:drawAnimation forKey:@"drawCircleAnimation"];
}
- (IBAction)changeStroke:(UIButton *)sender {
[self animateToPercentWayAround:sender.tag];
}
这是子类化CAShapeLayer的代码,
-(instancetype)initWithFrame:(CGRect) frame color:(CGColorRef) color lineWidth:(CGFloat) lineWidth {
if (self = [super init]) {
self.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(frame, 1, 1)].CGPath;
self.fillColor = [UIColor clearColor].CGColor;
self.strokeColor = color;
self.lineWidth = lineWidth;
self.strokeStart = 0;
self.strokeEnd = 0;
}
return self;
}