52

iPhone のアイコンを押したときに揺れるように、アプリケーション内で画像を前後に揺らしたいと考えています。それを行う最善の方法は何ですか?

これは、アニメーション GIF を使用しないアニメーションへの私の最初の進出です。画像を前後にわずかに回転させて、ウォブリング効果を作成するというアイデアだと思います。CABasicAnimation と CAKeyframeAnimation の使用を検討しました。CABasicAnimation は、元の位置にジャンプし、元の位置に補間しないため、繰り返すたびにジッターを作成します。CAKeyframeAnimation は、動作させることができないことを除けば、解決策のようです。私は何かが欠けているに違いない。CAKeyframeAnimation を使用したコードは次のとおりです (これは機能しません)。

    NSString *keypath = @"wobbleImage";
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:keypath];
animation.duration = 1.0f;
animation.delegate = self;
animation.repeatCount = 5;

CGFloat wobbleAngle = 0.0872664626f;
NSValue *initial = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 0.0f, 0.0f, 1.0f)];
NSValue *middle = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f)];
NSValue *final = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f)];
animation.values = [NSArray arrayWithObjects:initial, middle, final, nil];

[imageView.layer addAnimation:animation forKey:keypath];


または、私が見逃している完全に単純な解決策があるかもしれません。ポインタに感謝します。ありがとう!

4

13 に答える 13

92

それを行う簡単な方法:

#define RADIANS(degrees) (((degrees) * M_PI) / 180.0)

CGAffineTransform leftWobble = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(-5.0));
CGAffineTransform rightWobble = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(5.0));

itemView.transform = leftWobble;  // starting point

[UIView beginAnimations:@"wobble" context:itemView];
[UIView setAnimationRepeatAutoreverses:YES]; // important
[UIView setAnimationRepeatCount:10];
[UIView setAnimationDuration:0.25];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(wobbleEnded:finished:context:)];

itemView.transform = rightWobble; // end here & auto-reverse

[UIView commitAnimations];

...

- (void) wobbleEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context 
{
     if ([finished boolValue]) {
        UIView* item = (UIView *)context;
        item.transform = CGAffineTransformIdentity;
     }
}

おそらくタイミングと角度で遊ぶ必要がありますが、これで始めることができます。

編集:応答を編集してコードを追加し、完了時にアイテムを元の状態に戻しました。beginAnimationsまた、コンテキスト値を使用して、start/stopメソッドに何かを渡すことができることに注意してください。この場合、それはウォブリングオブジェクト自体であるため、特定のivarに依存する必要はなく、このメソッドは一般的なUIViewベースのオブジェクト(テキストラベル、画像など)に使用できます。

于 2009-05-30T16:54:40.460 に答える
92

Ramin の答えは非常に良かったのですが、OS4 以降では、1 つの単純な関数でも animateWithDuration を使用して同じ効果を実現できます。

(将来のグーグル社員のために彼の例を適応させた)

#define RADIANS(degrees) (((degrees) * M_PI) / 180.0)

- (void)startWobble {
 itemView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(-5));

 [UIView animateWithDuration:0.25 
      delay:0.0 
      options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse)
      animations:^ {
       itemView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(5));
      }
      completion:NULL
 ];
}

- (void)stopWobble {
 [UIView animateWithDuration:0.25
      delay:0.0 
      options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear)
      animations:^ {
       itemView.transform = CGAffineTransformIdentity;
      }
      completion:NULL
  ];
}
于 2011-04-19T20:29:28.923 に答える
14

CAKeyframeAnimationより滑らかなアニメーションを作成するために使用する必要があります。

+ (void) animationKeyFramed: (CALayer *) layer 
                   delegate: (id) object
              forKey: (NSString *) key {

    CAKeyframeAnimation *animation;
    animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
    animation.duration = 0.4;
    animation.cumulative = YES;
    animation.repeatCount = 2;
    animation.values = [NSArray arrayWithObjects:
            [NSNumber numberWithFloat: 0.0], 
            [NSNumber numberWithFloat: RADIANS(-9.0)], 
            [NSNumber numberWithFloat: 0.0],
            [NSNumber numberWithFloat: RADIANS(9.0)],
            [NSNumber numberWithFloat: 0.0], nil];
    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.removedOnCompletion = NO;
    animation.delegate = object;

    [layer addAnimation:animation forKey:key];
}
于 2011-01-07T22:08:27.130 に答える
4

最近この投稿に出くわし、Swift で同じことをしたいと思っている人のために、ここに私の翻訳を示します。

func smoothJiggle() {

    let degrees: CGFloat = 5.0
    let animation = CAKeyframeAnimation(keyPath: "transform.rotation.z")
    animation.duration = 0.6
    animation.cumulative = true
    animation.repeatCount = Float.infinity
    animation.values = [0.0,
        degreesToRadians(-degrees) * 0.25,
        0.0,
        degreesToRadians(degrees) * 0.5,
        0.0,
        degreesToRadians(-degrees),
        0.0,
        degreesToRadians(degrees),
        0.0,
        degreesToRadians(-degrees) * 0.5,
        0.0,
        degreesToRadians(degrees) * 0.25,
        0.0]
    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    animation.removedOnCompletion = true

    layer.addAnimation(animation, forKey: "wobble")
}

func stopJiggling() {
    jiggling = false
    self.layer.removeAllAnimations()
    self.transform = CGAffineTransformIdentity
    self.layer.anchorPoint = CGPointMake(0.5, 0.5)
}
于 2015-07-28T11:25:57.727 に答える
2

私が知っている最も簡単な方法は、Core Animation を使用することです。基本的に、コア アニメーション ブロックを作成し、次に回転変換を行い、セットアップと繰り返し回数を設定します。Core Animation は、このウォブリング エフェクトを実行するために必要なすべての処理を行います。

Core Animation ブロックを開始するには、次のようにします。

[UIView beginAnimations:@"any string as animationID" context:self];
[UIView setAnimationRepeatCount:10];
// rotate 
[UIView commitAnimations];

未検証。ただし、次のことも行う必要がある場合があります。

[UIView setAnimationBeginsFromCurrentState:YES];

AFAIK setAnimationRepeatCount には、指定した回数だけアニメーションが完了、元に戻す、完了、元に戻す、完了、元に戻す、完了という効果があります。したがって、最初はリピート カウントなしで左に回転させ、次にこの時点からリピート カウントでウォブリングを開始することができます。完了したら、回転して恒等変換に戻すことができます (= 回転とスケーリングは適用されません)。

でアニメーション デリゲートを設定することで、アニメーションを連鎖させることができます。

[UIView setAnimationDelegate:self]

その後

[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];

アニメーションが停止するとすぐに、そのメソッドが呼び出されます。アニメーションが停止したときに呼び出されるメソッドを実装する方法については、UIView クラスのドキュメントを参照してください。基本的に、そのメソッド内で次のステップ (つまり、元に戻すなど) を実行し、新しいアニメーション ブロックを使用しますが、同じコンテキストとアニメーション ID を使用し、(必要に応じて) 別の didStopSelector を指定します。

アップデート:

あなたはチェックアウトしたいかもしれません:

[UIView setAnimationRepeatAutoreverses:YES];

これは自動的に前後に揺れます。

于 2009-05-30T16:30:48.910 に答える
1

パーティーに遅刻。私は通常、ダンピング付きのスプリングを使用しています (iOS7 以降)。迅速にそれは次のようになります:

    sender.transform = CGAffineTransformMakeScale(1.2, 1.2)
    UIView.animateWithDuration(0.30, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.3, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
        sender.transform = CGAffineTransformMakeScale(1, 1)
    }) { (Bool) -> Void in
    //Do stuff when animation is finished
    }

initialSpringVelocityとを調整することで効果を微調整できます。SpringWithDamping

于 2016-05-28T13:23:16.713 に答える
0

Raminによって提供されたコードはうまく機能しますが、タブバー アプリケーションを使用して次のタブ項目に移動し、再び前のタブ項目に戻ると、ビューが毎回左に移動していることがわかります。したがって、ベスト プラクティスは次のとおりです。 ViewWillAppear メソッドを使用します。

- (void)viewWillAppear:(BOOL)animated
{
    UIView* item = self.view;
    item.transform = CGAffineTransformIdentity;
}

ビューが読み込まれるたびに、適切な場所にアニメーションが表示されます。また、この方法も使用してください。

[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];
于 2010-11-20T11:27:54.177 に答える