更改正在运行的animation的持续时间(速度)

我正在做一个无限期的旋转animation,当我第一次启动的时候,这个animation效果非常好。 我想实现的是能够在运行时改变旋转速度。 我在animationView中有这个function:

-(void)startBlobAnimation:(float)deltaT { [UIView beginAnimations:@"Spinning" context:nil]; [UIView setAnimationCurve:UIViewAnimationCurveLinear]; [UIView setAnimationDuration:deltaT]; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView setAnimationRepeatCount:FLT_MAX]; CGAffineTransform rotation = CGAffineTransformMakeRotation(-symmetryAngle); blobView.transform = rotation; // Commit the changes and perform the animation. [UIView commitAnimations]; } 

在animation首次启动后用不同的deltaT值调用没有任何影响。 如果我添加[wheelView.layer removeAllAnimations]; 在函数的开始,然后它成功地停止animation,但不重新启动它。 我也尝试使用block命令来启动animation,结果相同。 在这一点上,我完全感到困惑。 有人可以解释问题是什么吗? 谢谢!

经过漫长的斗争,我想出了一个解决scheme,似乎完美的工作,并给animation之间的平滑过渡。 基本上我只是找出当前的旋转angular度,并以不同的速度重新开始animation。 这里最重要的一点是最后一行:你必须在那里有anim.keyPath – 不能是Nil(从经验中学习)。 这样,我猜,新的animation会取代旧的animation。 噢,并且使它更加清楚:symmetryAngle是一个旋转,使对象看起来相同,如72度5倍对称。

 -(void)startWheelsAnimation:(float)deltaT { float startingAngle = 0.0; if(isAnimating) { // If animation is in progress then calculate startingAngle to // reflect the current angle of rotation CALayer *presLayer = (CALayer*)[blobView.layer presentationLayer]; CATransform3D transform = [presLayer transform]; startingAngle = atan2(transform.m12, transform.m11); } isAnimating = YES; // Restart the animation with different duration, and so that it starts // from the current angle of rotation CABasicAnimation * anim = [ CABasicAnimation animationWithKeyPath:@"transform.rotation.z" ] ; anim.duration = deltaT; anim.repeatCount = CGFLOAT_MAX; anim.fromValue = @(startingAngle); anim.toValue = @(startingAngle - symmetryAngle) ; [blobView.layer addAnimation:anim forKey:anim.keyPath]; } 

2017年

改变CAanimation运行的速度。

这就是我如何做“亚历克斯方法”…

我有一个形状层

 @IBDesignable class SpinningThing: UIView { public func runAnimation() { // call this from the view controller, say speedy = 1.0 startFastThenSlowDown() } override func layoutSubviews() { super.layoutSubviews() setup() } func setup() { setup .. other stuff (draw things) setupThingThatSpins() } var thingThatSpins = CAShapeLayer() var speedy = 0.5 // start fast var finalSpeed = 13.0 // final slow speed func setupThingThatSpins() { let p = UIBezierPath( .. etc etc thingThatSpins.strokeColor .. etc etc // so actually draw the thingThatSpins } 

这里是startFastThenSlowDown发生的startFastThenSlowDown

 func startFastThenSlowDown() { speedy *= 1.175 animeSpinRestartable(spr: speedy) if speedy < finalSpeed { delay(0.1) { self._slowDown() } } } 

现在,这是一个可重新启动的animation,感谢Alex …

 func animeSpinRestartable(spr: CFTimeInterval) { let _key = "animeSpinRestartable" thingThatSpins.removeAnimation(forKey: _key) // is safe the first time through // get the current angle... let t3 = arcs.presentation()?.transform let cur = (t3 == nil) ? 0 : atan2(t3!.m12, t3!.m11) let r = _typicalAnim(keyPath: "transform.rotation.z") r.fromValue = cur r.toValue = cur + 2 * CGFloat.pi r.duration = spr ///r.isCumulative = true ? seems unnecessary, so don't do it thingThatSpins.add(r, forKey: _key) } 

在我的例子中, thingThatSpins是一个面具(为了上帝的缘故),它在别的东西之上(一个颜色渐变,本身就是animation的!)

好的,OP。

几个问题 –

  • 我想无尽的animation,你将不得不直接使用CoreAnimation API。 (这是不正确的,你可以使用UIViewAnimationOptionRepeat)

  • animation被复制到它们应用的图层,所以你不能在之后改变它们(你可以replace它们,但是你可能会看到一个不连续性)

  • 您可以设置layer.speed来更改有效的animation速率

这是一个工作的例子。 在Xcode中创build一个新的“空白”iOS项目,并像这样replace你的AppDelegate:

 @interface AppDelegate () @property ( nonatomic, strong ) UIView * animationView ; @end @implementation AppDelegate -(void)buttonClicked { self.animationView.layer.speed = 3.0 - self.animationView.layer.speed ; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; CGRect bounds = self.window.bounds ; { UIView * subview = [ [ UIView alloc ] initWithFrame:(CGRect){ .size = { 100, 100 } } ] ; [ self.window addSubview:subview ] ; subview.backgroundColor = [ UIColor orangeColor ] ; subview.center = (CGPoint){ CGRectGetMidX( bounds ), CGRectGetMidY( bounds ) } ; CABasicAnimation * anim = [ CABasicAnimation animationWithKeyPath:@"transform.rotation.z" ] ; anim.duration = 1.0 ; anim.repeatCount = CGFLOAT_MAX ; anim.fromValue = @0.0 ; anim.toValue = @(2.0*M_PI) ; [ subview.layer addAnimation:anim forKey:nil ] ; self.animationView = subview ; } UIControl * button = [[ UIControl alloc ] initWithFrame:bounds ] ; [ button addTarget:self action:@selector( buttonClicked ) forControlEvents:UIControlEventTouchUpInside ] ; [ self.window addSubview:button ] ; return YES; } @end