web-dev-qa-db-ja.com

autoreverseによるUIViewアニメーション

UIViewAnimationOptionAutoReverseの設定に問題があります。これが私のコードです。

CALayer *aniLayer = act.viewToChange.layer;
[UIView animateWithDuration:2.0 delay:1.0 options:(UIViewAnimationCurveLinear | UIViewAnimationOptionAutoreverse) animations:^{
                    viewToAnimate.frame = GCRectMake(1,1,100,100);
                    [aniLayer setValue:[NSNumber numberWithFloat:degreesToRadians(34)] forKeyPath:@"transform.rotation"];
                } completion:nil ];

問題は、アニメーションが反転した後、ビューがアニメーションブロックに設定されたフレームにジャンプして戻ることです。私は、ビューが成長して「伸びて」元の位置に止まるようにしたいと考えています。

2つの連続したアニメーションをプログラミングしないで解決策はありますか?

38
Stultus

3つのオプションがあります。

-[UIView animateWithDuration:…]メソッドを使用すると、animationsブロックで行った変更が問題のビューにすぐに適用されます。ただし、古い値から新しい値にアニメーション化する暗黙のCAAnimationもビューに適用されます。 CAAnimationがビューでアクティブな場合、displayedビューは変更されますが、ビューの実際のプロパティは変更されません。

たとえば、次のようにした場合:

NSLog(@"old center: %@", NSStringFromCGPoint(someView.center));
[UIView animateWithDuration:2.0 animations: ^{ someView.center = newPoint; }];
NSLog(@"new center: %@", NSStringFromCGPoint(someView.center));

「旧センター」と「新センター」が異なることがわかります。新しい中心はすぐにnewPointの値を反映します。ただし、暗黙的に作成されたCAAnimationを使用すると、ビューは引き続き古い中心に表示され、スムーズに移動します。新しいセンター。アニメーションが終了すると、ビューから削除され、実際のモデル値を表示するだけに戻ります。

UIViewAnimationOptionAutoreverseを渡すと、暗黙的に作成されたCAAnimationに影響しますが、値に対して行っている実際の変更には影響しません。つまり、上記の例でUIViewAnimationOptionAutoreverseが定義されている場合、暗黙的に作成されたCAAnimationは、oldCenterからnewCenterにアニメーション化して戻ります。その後、アニメーションが削除され、設定した値を表示するように戻ります…まだ新しい位置にあります

私が言ったように、これに対処するには3つの方法があります。 1つ目は、アニメーションに完了ブロックを追加して、次のように反転させることです。

最初のオプション

CGPoint oldCenter = someView.center;
[UIView animateWithDuration:2.0
                 animations: ^{ someView.center = newPoint; }
                 completion: 
   ^(BOOL finished) {
       [UIView animateWithDuration:2.0
                        animations:^{ someView.center = oldCenter; }];
   }];

2番目のオプション

2番目のオプションは、アニメーションを自動反転して、完了ブロックでビューを元の位置に戻すことです。

CGPoint oldCenter = someView.center;
[UIView animateWithDuration:2.0
                      delay:0
                    options: UIViewAnimationOptionAutoreverse
                 animations: ^{ someView.center = newPoint; }
                 completion: ^(BOOL finished) { someView.center = oldCenter; }];

ただし、これにより、アニメーションの自動反転が完了してから完了ブロックが実行されるまでの間にちらつきが発生する可能性があるため、おそらく最良の選択ではありません。

3番目のオプション

最後のオプションは、単純にCAAnimationを直接作成することです。変更するプロパティの最終的な値を実際に変更したくない場合、これは多くの場合より簡単です。

#import <QuartzCore/QuartzCore.h>

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.autoreverses = YES;
animation.repeatCount = 1; // Play it just once, and then reverse it
animation.toValue = [NSValue valueWithCGPoint:newPoint];
[someView.layer addAnimation:animation forKey:nil];

CAAnimationの方法でビューの実際の値が変更されることはありません。実際の値をアニメーションでマスクするだけです。ビューはまだ元の場所にあると考えています。 (たとえば、ビューがタッチイベントに応答する場合、それらのタッチイベントが元の場所で発生するのを引き続き監視します。アニメーションのみビューの描画方法を変更します。それ以外は何も変更しません。

CAAnimation方法では、ビューの基礎となるCALayerに追加する必要もあります。これが怖い場合は、代わりに-[UIView animateWithDuration:…]メソッドを使用してください。 CAAnimationを使用して追加の機能を利用できますが、慣れていない場合は、UIViewアニメーションをチェーンするか、完了ブロックでリセットすることで問題ありません。実際、これは完了ブロックの主な目的の1つです。

だから、あなたは行き​​ます。アニメーションを元に戻し、元の値を維持する3つの方法。楽しい!

95
BJ Homer

これが私の解決策です。 2倍の繰り返しの場合、1.5倍のアニメーションを作成し、最後の0.5倍の部分を自分で行います。

[UIView animateWithDuration:.3
                      delay:.0f
                    options:(UIViewAnimationOptionRepeat|
                             UIViewAnimationOptionAutoreverse)
                 animations:^{
                     [UIView setAnimationRepeatCount:1.5f];

                     ... animate here ...

                 } completion:^(BOOL finished) {
                         [UIView animateWithDuration:.3 animations:^{

                             ... finish the animation here ....

                         }];
                 }];

点滅しません、うまくいきます。

14

repeatCountにはCAMediaTimingプロパティがあります。明示的なCAAnimationオブジェクトを作成し、適切に構成する必要があると思います。 growおよびungrowのrepeatCountは2になりますが、これをテストできます。

これの長い何か。ただし、フレーム用と回転用の2つのCAAnimationオブジェクトが必要です。

CABasicAnimation *theAnimation;

theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation"];
theAnimation.duration=3.0;
theAnimation.repeatCount=1;
theAnimation.autoreverses=YES;
theAnimation.fromValue=[NSNumber numberWithFloat:0.0];
theAnimation.toValue=[NSNumber numberWithFloat:degreesToRadians(34)];
[theLayer addAnimation:theAnimation forKey:@"animateRotation"];

私の知る限り、2つのアニメーションオブジェクトのプログラミングを回避する方法はありません。

0
GorillaPatch