UIViewシェイクアニメーション


82

ボタンが押されたときにUIViewをシェイクさせようとしています。

http://www.cimgf.com/2008/02/27/core-animation-tutorial-window-shake-effect/で見つけたコードを適応させています

ただし、次のコードを適応させてUIViewをシェイクしようとすると、機能しません。

- (void)animate {
    const int numberOfShakes = 8;
    const float durationOfShake = 0.5f;
    const float vigourOfShake = 0.1f;

    CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animation];

    CGRect frame = lockView.frame;

    CGMutablePathRef shakePath = CGPathCreateMutable();
    CGPathMoveToPoint(shakePath, NULL, CGRectGetMinX(frame), CGRectGetMinY(frame));

    for (int index = 0; index < numberOfShakes; ++index) {
        CGPathAddLineToPoint(shakePath, NULL, CGRectGetMinX(frame) - frame.size.width * vigourOfShake, CGRectGetMinY(frame));

        CGPathAddLineToPoint(shakePath, NULL, CGRectGetMinX(frame) + frame.size.width * vigourOfShake, CGRectGetMinY(frame));
    }

    CGPathCloseSubpath(shakePath);

    shakeAnimation.path = shakePath;
    shakeAnimation.duration = durationOfShake;


    [lockView.layer addAnimation:shakeAnimation forKey:@"frameOrigin"];

}

回答:


204

私はその投稿を書きました。UIViewにとってはやり過ぎであり、さらにパラメーターはOSXアプリを対象としています。代わりにこれを行ってください。

CABasicAnimation *animation = 
                         [CABasicAnimation animationWithKeyPath:@"position"];
[animation setDuration:0.05];
[animation setRepeatCount:8];
[animation setAutoreverses:YES];
[animation setFromValue:[NSValue valueWithCGPoint:
               CGPointMake([lockView center].x - 20.0f, [lockView center].y)]];
[animation setToValue:[NSValue valueWithCGPoint:
               CGPointMake([lockView center].x + 20.0f, [lockView center].y)]];
[[lockView layer] addAnimation:animation forKey:@"position"];

期間とrepeatCountパラメーター、およびfromとtoの値の中心からのx距離を操作する必要がありますが、必要なものが得られるはずです。それがお役に立てば幸いです。ご不明な点がございましたらお知らせください。

---


Swift 3.0

let midX = lockView.center.x
let midY = lockView.center.y

let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.06
animation.repeatCount = 4
animation.autoreverses = true
animation.fromValue = CGPoint(x: midX - 10, y: midY)
animation.toValue = CGPoint(x: midX + 10, y: midY)
layer.add(animation, forKey: "position")

おかげで、私は誰もがそれを使用したい場合Xamarin IOSでそれを構築するためにあなたの答えを使用して、ここにある:gist.github.com/jorwan/1ed57459c7b01b5a5b1135219e6219cf
ホルヘワンダサンタナUreña

@Mattランダムにシェイクしたい場合、UIViewは各シェイクでランダムな方向に移動しますか?
Ehtesham Hasan 2017

@EhteshamHasanそれは本当にランダムではありえませんでした。位置/ポイントは範囲内にある必要があり、その範囲の両極端(コーナーからコーナーなど)の間で揺れたくない場合があります(それはあなた次第ですが)。簡単な答えは、可能な位置(CGPoints)を配列に配置し、配列内のポイントの数よりも少ないインデックスを提供する乱数ジェネレーターをシードしてから、私の答えで説明したのと同じ手法を使用して位置をそのポイントに移動します。
マットロング

78

私は、パスワードを間違えたシェイクアニメーションに最適な、弾力性のある優れた動作を備えたこのソリューションを好みます。

view.transform = CGAffineTransformMakeTranslation(20, 0);
[UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.2 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
    view.transform = CGAffineTransformIdentity;
} completion:nil];

スウィフト3

extension UIView {
    func shake() {
        self.transform = CGAffineTransform(translationX: 20, y: 0)
        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
            self.transform = CGAffineTransform.identity
        }, completion: nil)
    }
}

これをどのように繰り返しますか?それは今一度だけ起こります。
Crashalot 2016

1
私がOPを正しく理解していれば、彼は短いシェイクアニメーションを望んでいました。実生活では、揺れの動きには摩擦があり、時間の経過とともに遅くなるので、私の解決策が最も適切だと思います。揺れを長くしたい場合は、ダンピングとinitialVelocityパラメーターを試してください。それを無期限に繰り返したい場合は、他の解決策の1つを使用してください。
Ortwin Gentz 2016

このアニメーションは最高でした、同意しました。数回繰り返したいだけです、それだけです。
Crashalot 2016

延長したいだけの場合は、デュレーション、ダンピング、initialVelocityの値を試してみてください。
Ortwin Gentz 2016

1
このソリューションは、完了ハンドラーを使用できるため、はるかに優れています。
ユーリグリゴリエフ2018

34

これが私の見栄えの良いシンプルなバージョンです。これは、間違ったログインを行ったときにMac OSXで発生する揺れをシミュレートします。必要に応じて、これをUIViewのカテゴリとして追加できます。

@implementation UIView (DUExtensions)

- (void) shake {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.duration = 0.6;
    animation.values = @[ @(-20), @(20), @(-20), @(20), @(-10), @(10), @(-5), @(5), @(0) ];
    [self.layer addAnimation:animation forKey:@"shake"];  
}

@end

アニメーション値は、ビューの現在の位置からのxオフセットです。正の値はビューを右にシフトし、負の値は左にシフトします。それらを連続的に下げることにより、自然に勢いを失う揺れが得られます。必要に応じて、これらの数値を微調整できます。


1
これをUIViewカテゴリに埋め込むための見栄えとサウンドのアイデア。UIViewsは揺れるはずです、期間!
ペドロボルヘス

低速(つまり、長時間)で使用すると、このアニメーションは、repeatCountを使用する他の回答のアニメーションよりもはるかにスムーズになります。
テオ

このコードを使用した後のいくつかの考え。タイミング機能-デフォルトは線形であるため、設定する必要はありません。アニメーション値-さらに一歩進んで、関数を定義して素晴らしい数学値を生成することができます...これも機能します:)
ジョーダンスミス

17

誰かがそれを必要とする場合に備えて、拡張機能としての迅速なバージョンがあります

extension UIImageView{
    func vibrate(){
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 0.05
        animation.repeatCount = 5
        animation.autoreverses = true
        animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 2.0, self.center.y))
        animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 2.0, self.center.y))
        self.layer.addAnimation(animation, forKey: "position")
    }
}

これにより、小さなUIImageView(約15x15)がアニメーション化されます。より大きなものをアニメートする必要がある場合は、2.0の動きの係数をより大きなものに変更することをお勧めします。


8

@bandejapaisaの回答に基づいて、Swift3のUIView拡張機能

extension UIView {
    func shake() {
        let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.duration = 0.6
        animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
        layer.addAnimation(animation, forKey: "shake")
    }
}

4

このコードを試すことができます:

以下のコードを呼び出すには、次を使用します。 [self earthquake:myObject];

#pragma mark EarthQuake Methods

- (void)earthquake:(UIView*)itemView
{
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); 

    CGFloat t = 2.0;

    CGAffineTransform leftQuake  = CGAffineTransformTranslate(CGAffineTransformIdentity, t, -t);
    CGAffineTransform rightQuake = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, t);

    itemView.transform = leftQuake;  // starting point

    [UIView beginAnimations:@"earthquake" context:itemView];
    [UIView setAnimationRepeatAutoreverses:YES]; // important
    [UIView setAnimationRepeatCount:3];
    [UIView setAnimationDuration:0.05];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(earthquakeEnded:finished:context:)];

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

    [UIView commitAnimations];
}

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

4

UIButtonクリックイベントでこのメソッドを呼び出すことができます

-(void)shakescreen
{
    //Shake screen
    CGFloat t = 5.0;
    CGAffineTransform translateRight = CGAffineTransformTranslate(CGAffineTransformIdentity, t, t);
    CGAffineTransform translateLeft = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, -t);

    self.view.transform = translateLeft;

    [UIView animateWithDuration:0.05 delay:0.0 options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^
    {
         [UIView setAnimationRepeatCount:2.0];
         self.view.transform = translateRight;
    } completion:^(BOOL finished)

      {
          if (finished) 
          {
             [UIView animateWithDuration:0.05 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
          {
              self.view.transform = CGAffineTransformIdentity;
          } 
          completion:NULL];
      }
  }];
}

これがお役に立てば幸いです:-)


3

iOSでUIViewシェイクアニメーションを作成する方法回答のC#Xamarin.iOSバージョンは以下のとおりです

        CAKeyFrameAnimation keyframeAnimation = CAKeyFrameAnimation.GetFromKeyPath(new NSString("transform.translation.x"));
        keyframeAnimation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut);
        keyframeAnimation.Duration = 0.6f;
        keyframeAnimation.Values = new NSObject[]{ new NSNumber(-20f), new NSNumber(20f), new NSNumber(-20f), new NSNumber(20f), new NSNumber(-10f), new NSNumber(10f), new NSNumber(-5f), new NSNumber(5f), new NSNumber(0f) };
        shakyView.Layer.AddAnimation(keyframeAnimation, "shake");

2

これは、ダンパー機能を使用して揺れを減衰させるものです。

- (void)shake
{
    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.duration = 0.5;
    animation.delegate = self;
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = YES;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

    NSMutableArray* values = [[NSMutableArray alloc] init];

    int steps = 100;
    double position = 0;
    float e = 2.71;

    for (int t = 0; t < steps; t++)
    {
        position = 10 * pow(e, -0.022 * t) * sin(0.12 * t);
        NSValue* value = [NSValue valueWithCGPoint:CGPointMake([self center].x - position, [self center].y)];
        DDLogInfo(@"Value: %@", value);
        [values addObject:value];
    }

    animation.values = values;
    [[self layer] addAnimation:animation forKey:@"position"];

}

2

@Matt Longコードをリファクタリングし、カテゴリをに作成しましたUIView。今では、はるかに再利用可能で使いやすいです。

@implementation UIView (Animation)

- (void)shakeViewWithOffest:(CGFloat)offset {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    [animation setDuration:0.05];
    [animation setRepeatCount:6];
    [animation setAutoreverses:YES];
    [animation setFromValue:@([self center].x-offset)];
    [animation setToValue:@([self center].x+offset)];

    [self.layer addAnimation:animation forKey:@"position.x"];
}

- (void)shake {
    [self shakeViewWithOffest:7.0f];
}
@end

2

@Mihaelに基づくSwift3の実装-Isaevの回答

private enum Axis: StringLiteralType {
    case x = "x"
    case y = "y"
}

extension UIView {
    private func shake(on axis: Axis) {
        let animation = CAKeyframeAnimation(keyPath: "transform.translation.\(axis.rawValue)")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.duration = 0.6
        animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
        layer.add(animation, forKey: "shake")
    }
    func shakeOnXAxis() {
        self.shake(on: .x)
    }
    func shakeOnYAxis() {
        self.shake(on: .y)
    }
}

2

Swift4.2での@imikeの回答

extension UIView {
func shake() {
    let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    animation.duration = 0.6
    animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
    self.layer.add(animation, forKey: "shake")
}}

1
最後の行はself.layer.add(アニメーション、forKey:「シェイク」)で固定されなければならない
ilkayaktas

1

次のコードを試すことができます。

+ (void)vibrateView:(UIView*)view
{
    CABasicAnimation *shiverAnimationR;
    shiverAnimationR = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    shiverAnimationR.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(1)];
    //shiverAnimationR.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(-10)];
    shiverAnimationR.duration = 0.1;
    shiverAnimationR.repeatCount = 1000000.0; // Use A high Value
    shiverAnimationR.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

    [view.layer addAnimation: shiverAnimationR forKey:@"shiverAnimationR"];

    CABasicAnimation * shiverAnimationL;
    shiverAnimationL = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    //shiverAnimationL 2.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(10)];
    shiverAnimationL.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(-1)];
    shiverAnimationL.duration = 0.1;
    shiverAnimationL.repeatCount = 1000000.0;
    shiverAnimationL.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

    [view.layer addAnimation: shiverAnimationL forKey:@"shiverAnimationL"];

}

リンクから。


1

これは、を使用したバージョンです。

+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

iOS7で導入されました。

    const CGFloat xDelta = 16.0f;

    [UIView animateKeyframesWithDuration:0.50f
                                   delay:0.0f
                                 options:UIViewKeyframeAnimationOptionCalculationModeLinear
                              animations:^{

                                  [UIView addKeyframeWithRelativeStartTime:0.0
                                                          relativeDuration:(1.0/6.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(xDelta, 0.0);
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:(1.0/6.0)
                                                          relativeDuration:(1.0/6.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(-xDelta, 0.0);
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:(1.0/3.0)
                                                          relativeDuration:(1.0/3.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(xDelta/2.0, 0.0);
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:(2.0/3.0)
                                                          relativeDuration:(1.0/3.0)
                                                                animations:^{
                                                                    self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformIdentity;
                                                                }];

                              }
                              completion:NULL];


1

Swift 4.0:

一番上の答えに基づいていますが、アニメーションを改良しています。これには、アニメーションの開始時と終了時のジャンプはありません。

    let midX = center.x
    let midY = center.y

    let rightAnim = CABasicAnimation(keyPath: #keyPath(CALayer.position))
    rightAnim.duration      = 0.07
    rightAnim.autoreverses  = true
    rightAnim.fromValue     = CGPoint(x: midX, y: midY)
    rightAnim.toValue       = CGPoint(x: midX + 9, y: midY)

    let leftAnim = CABasicAnimation(keyPath: #keyPath(CALayer.position))
    leftAnim.duration       = 0.07
    leftAnim.autoreverses   = true
    leftAnim.fromValue      = CGPoint(x: midX, y: midY)
    leftAnim.toValue        = CGPoint(x: midX - 9, y: midY)

    let group = CAAnimationGroup()
    group.duration      = leftAnim.duration + rightAnim.duration
    group.animations    = [rightAnim, leftAnim]
    group.repeatCount   = 3

    layer.add(group, forKey: #keyPath(CALayer.position))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.