简体   繁体   English

UIView使用自定义drawRect和animateWithDuration

[英]UIView with custom drawRect and animateWithDuration

I have a UIView subclass that displays circular progress: 我有一个显示循环进度的UIView子类:

循环进度视图

Screenshot above shows progress with value of 0.667 . 上面的屏幕截图显示了值为0.667进度。

Inside my UIView subclass implementation in drawRect: method I am drawing two circles - one for background oval (gray), second for actual progress oval (blue). drawRect:方法中我的UIView子类实现内部我绘制了两个圆 - 一个用于背景椭圆(灰色),第二个用于实际进度椭圆(蓝色)。 (Check out source code) (查看源代码)

It works like expected, but doesn't allow to animate progress changes. 它的工作方式与预期相同,但不允许对进度更改进行动画处理。 I tried to find solution that allows using UIView 's animateWithDuration:animations: class method like this: 我试图找到允许使用UIViewanimateWithDuration:animations:解决方案animateWithDuration:animations:类方法:

MyCustomView *progressView = ...
[UIView animateWithDuration:3 
                 animations:^{
                     progressView.progressValue = 1.f;
                 }];

But I wasn't able to make it animates that way. 但我无法以这种方式制作动画。

You can check out the source code in my GitHub repository . 您可以在我的GitHub存储库中查看源代码。

However, I found a way to perform an animation whenever progressValue changes. 但是,我发现了一种在progressValue发生变化时执行动画的方法。 It's not exactly what I want (still not working with UIView 's animateWithDuration:animations: ), and I am not sure if this is the right direction. 这不是我想要的(仍然没有使用UIViewanimateWithDuration:animations: ,我不确定这是否是正确的方向。 It involves subclassing CALayer of my UIView . 它涉及子类化我的UIView CALayer You can check out the source code in the same repo mentioned above, on custom_layer branch . 您可以在custom_layer分支上查看上面提到的同一个repo中的源代码。 Here is direct link to CALayer subclass drawing implementation. 这是CALayer子类绘图实现的直接链接

My question is: Having a UIView subclass that draws some shapes based on custom properties ( progressValue ), is it possible to make the view animates with UIView 's animateWithDuration:animations: when changing the view's property ( progressValue ) ? 我的问题是:有一个基于自定义属性( progressValue )绘制一些形状的UIView子类,是否可以使用UIViewanimateWithDuration:animations:进行视图动画animateWithDuration:animations:更改视图的属性( progressValue )?

UPDATE UPDATE

Thanks to rounak's answer I get rid of drawing custom shapes in drawRect: method and created two separate CAShapeLayer s. 感谢rounak的回答,我摆脱了drawRect:方法中绘制自定义形状并创建了两个单独的CAShapeLayer Instead of drawing new shapes every time progressValue changes, I am just setting strokeEnd properties for that layers, which gives the same visual effect as before, but should perform better ( check out source code ). 我不是每次progressValue更改时都绘制新的形状,而只是为这些图层设置strokeEnd属性,它们提供与以前相同的视觉效果,但应该表现更好( 查看源代码 )。

Then I implemented actionForLayer:forKey: method ( check out source code ), which returns CABasicAnimation that should animate strokeEnd whenever progressValue changes. 然后我实现了actionForLayer:forKey:方法( 检查源代码 ),它返回CABasicAnimation ,它应该在progressValue改变时为strokeEnd设置动画。

However, I am still experiencing an issue with the animation: 但是,我仍然遇到动画问题:

__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];
                                      }];
                 }];

My circular progress view animates progressValue changes, and executing the code above tells that each animation takes about 3 seconds. 我的循环进度视图为progressValue更改设置动画,并执行上面的代码告诉每个动画大约需要3秒钟。 Unfortunately, on screen the view animates very fast (animation completes in fraction of a second). 不幸的是,在屏幕上,视图动画非常快(动画在几分之一秒内完成)。 Here is what it looks like: 这是它的样子:

在此输入图像描述

I am not sure where the problem is, but I noticed that changing keypath in [CABasicAnimation animationWithKeyPath:@"strokeEnd"] from strokeEnd to anything else doesn't gives any effect (animation always looks the same). 我不确定问题出在哪里,但我注意到将[CABasicAnimation animationWithKeyPath:@"strokeEnd"]strokeEndstrokeEnd为其他任何内容都不会产生任何效果(动画总是看起来一样)。

Any hints of what I am missing here will be appreciated. 任何我在这里缺少的提示将不胜感激。

UPDATE 2 更新2

I have just noticed that animation is in fact triggered by those two lines in setProgressValue: setter: 我刚刚注意到动画实际上是由setProgressValue:这两行触发的setProgressValue: setter:

self.progressOvalLayer.strokeEnd = MIN(1, MAX(0, progressValue));
self.backgroundOvalLayer.strokeEnd = MIN(1, MAX(0, 1 - progressValue));

( see on GitHub ) 参见GitHub

It looks like my implementation of actionForLayer:forKey: does not work at all, despite being executed (checked with brakepoint). 看起来我的actionForLayer:forKey:实现actionForLayer:forKey:尽管被执行了,但根本不起作用(用brakepoint检查)。

I wonder what I am doing wrong? 我想知道我做错了什么?

UPDATE - SOLUTION FOUND 更新 - 解决方案

It occurred that I tried to animate main layer of my UIView instead of custom layers that contains oval shapes. 我试图为我的UIView主图层设置动画,而不是包含椭圆形状的自定义图层。 I needed to fix actionForLayer:(CALayer *)layer forKey: implementation to make it works ( check out fixed source code ). 我需要修复actionForLayer:(CALayer *)layer forKey:实现使其工作( 检查固定的源代码 )。 That solves my problem. 这解决了我的问题。

I'd suggest you draw the circular progress with a CAShapeLayer , and use the strokeStart , strokeEnd , and fillColor properties to achieve your effect. 我建议你画一个圆形进度CAShapeLayer ,并使用strokeStartstrokeEnd ,并fillColor属性来实现你的效果。 You'll likely need two shapeLayers, one over the other, but the advantage with this approach is that shapeLayer's properties are animateable via CoreAnimation. 您可能需要两个shapeLayers,一个在另一个之上,但这种方法的优点是shapeLayer的属性可以通过CoreAnimation进行动画处理。

Additionally, you can use hackery like this to make it animate within animation blocks as well https://gist.github.com/nicklockwood/d374033b27c62662ac8d 此外,您可以使用这样的hackery在动画块中制作动画,以及https://gist.github.com/nicklockwood/d374033b27c62662ac8d

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM