UIView与自定义drawRect和animateWithDuration

时间:2015-04-26 18:28:37

标签: ios animation uiview core-animation calayer

我有一个显示循环进度的UIView子类:

circular progress view

上面的屏幕截图显示了值为0.667的进度。

UIView方法中的drawRect:子类实现中,我绘制了两个圆圈 - 一个用于背景椭圆形(灰色),第二个用于实际进展椭圆形(蓝色)。 (Check out source code)

它按预期工作,但不允许动画进度更改。我试图找到允许使用UIView的{​​{1}}类方法的解决方案:

animateWithDuration:animations:

但我无法以这种方式制作动画。

您可以在my GitHub repository中查看源代码。

但是,我找到了一种在MyCustomView *progressView = ... [UIView animateWithDuration:3 animations:^{ progressView.progressValue = 1.f; }]; 更改时执行动画的方法。这不是我想要的(仍然没有使用progressValue的{​​{1}}),我不确定这是否是正确的方向。它涉及对UIView的{​​{1}}进行子类化。您可以在上面提到的同一个repo on custom_layer branch中查看源代码。这是[{3}}到animateWithDuration:animations:子类绘图实现。

我的问题是:拥有一个基于自定义属性(CALayer)绘制一些形状的UIView子类,是否可以使用CALayer的{​​{1}制作视图动画更改视图的属性(UIView)?

更新

感谢direct link我摆脱了在progressValue方法中绘制自定义形状并创建了两个单独的UIView。我不是每次animateWithDuration:animations:更改时都会绘制新形状,而只是为这些图层设置progressValue属性,这会产生与以前相同的视觉效果,但应该效果更好(rounak's answer)。< / p>

然后我实施了drawRect:方法(check out source code),该方法会返回CAShapeLayerprogressValue会在strokeEnd更改时生成actionForLayer:forKey:

但是,我仍然遇到动画问题:

CABasicAnimation

我的循环进度视图动画strokeEnd更改,执行上面的代码告诉每个动画大约需要3秒钟。不幸的是,在屏幕上,视图动画非常快(动画在几分之一秒内完成)。这是它的样子:

enter image description here

我不确定问题出在哪里,但我注意到将progressValue中的密钥路径从__block NSDate *date = [NSDate date]; [UIView animateWithDuration:3 animations:^{ self.progressView.progressValue = 1.f; } completion:^(BOOL finished1) { NSLog(@"first animation completed in %f", [[NSDate date] timeIntervalSinceDate:date]); date = [NSDate date]; [UIView animateWithDuration:3 animations:^{ self.progressView.progressValue = 0.f; } completion:^(BOOL finished2) { NSLog(@"second animation completed in %f", [[NSDate date] timeIntervalSinceDate:date]); [self animateProgress]; }]; }]; 更改为其他任何内容都不会产生任何影响(动画总是看起来一样)。

我将不胜感激任何我在这里缺少的提示。

更新2

我刚才注意到动画实际上是由progressValue setter中的那两行触发的:

[CABasicAnimation animationWithKeyPath:@"strokeEnd"]

check out source code

看起来我strokeEnd的实现根本不起作用,尽管被执行了(用brakepoint检查)。

我想知道我做错了什么?

更新 - 解决方案

我试图为setProgressValue:的主图层设置动画,而不是包含椭圆形状的自定义图层。我需要修复self.progressOvalLayer.strokeEnd = MIN(1, MAX(0, progressValue)); self.backgroundOvalLayer.strokeEnd = MIN(1, MAX(0, 1 - progressValue)); 实现以使其有效(see on GitHub)。这解决了我的问题。

1 个答案:

答案 0 :(得分:2)

我建议您使用CAShapeLayer绘制循环进度,并使用strokeStartstrokeEndfillColor属性来实现效果。你可能需要两个shapeLayers,一个在另一个上,但这种方法的优点是shapeLayer的属性可以通过CoreAnimation动画化。

此外,您可以像这样使用hackery在动画块中制作动画https://gist.github.com/nicklockwood/d374033b27c62662ac8d