私はあなたがそれを押したときに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];
または、私が今見逃している完全にシンプルなソリューションがあるかもしれません。ポインターに感謝します。ありがとう!
簡単な方法:
#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ベースのオブジェクト(テキストラベル、画像など)に使用できます。
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
];
}
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];
}
ホーム画面のぐらつきとアイコンの動きを再現しようとするサンプルアプリを作成しました: iPhone Sample Code:Tiles
この投稿に最近出くわし、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)
}
私が知っている最も簡単な方法は、Core Animationを使用することです。基本的に、コアアニメーションブロックを作成してから、回転変換を行い、カウントを設定して繰り返します。その後、Core Animationが、このウォブリングエフェクトを実行するために必要なすべてを処理します。
Core Animationブロックを開始するには、次を実行します。
[UIView beginAnimations:@"any string as animationID" context:self];
[UIView setAnimationRepeatCount:10];
// rotate
[UIView commitAnimations];
未検証。ただし、次のことも必要になる場合があります。
[UIView setAnimationBeginsFromCurrentState:YES];
私の知る限り。 setAnimationRepeatCountには、指定した回数だけアニメーションが完了、元に戻す、完了、元に戻す、完了、元に戻す、完了...という効果があります。したがって、最初に繰り返しカウントなしで左に回転し、このポイントから繰り返しカウントでウォブリングを開始することができます。完了したら、回転してアイデンティティ変換に戻します(=回転とスケーリングは適用されません)。
アニメーションデリゲートを次のように設定することにより、アニメーションをチェーンできます。
[UIView setAnimationDelegate:self]
その後
[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];
アニメーションが停止するとすぐに、そのメソッドが呼び出されます。アニメーションが停止したときに呼び出されるメソッドを実装する方法については、UIViewクラスのドキュメントを参照してください。基本的に、そのメソッド内で、新しいアニメーションブロックで同じコンテキストとアニメーションIDを使用して次のステップ(つまり、回転バックなど)を実行し、(必要に応じて)別のdidStopSelectorを指定します。
更新:
あなたはチェックアウトしたいかもしれません:
[UIView setAnimationRepeatAutoreverses:YES];
これは自動的に行き来します。
CAKeyframeAnimation
を使用して、次のように無限のウォブル効果を作成できます。
CGFloat degrees = 8.0;
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.duration = 0.6;
animation.cumulative = YES;
animation.repeatCount = 1;
animation.values = @[@0.0,
@RADIANS(-degrees) * 0.25,
@0.0,
@RADIANS(degrees) * 0.5,
@0.0,
@RADIANS(-degrees),
@0.0,
@RADIANS(degrees),
@0.0,
@RADIANS(-degrees) * 0.5,
@0.0,
@RADIANS(degrees) * 0.25,
@0.0];
animation.fillMode = kCAFillModeForwards;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.removedOnCompletion = YES;
[self.layer addAnimation:animation forKey:@"wobble"];
パーティーに遅れて。私は通常、減衰機能付きのスプリングを使用しています(iOS7以降)。 Swiftのようになります:
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
を調整することにより、効果を微調整できます。
EsbenBの回答に基づきますが、Swift 3およびローテーション:
sender.transform = CGAffineTransform(rotationAngle: 12.0 * .pi / 180.0)
UIView.animate(withDuration: 0.60, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.3, options: .curveEaseInOut, animations: { () -> Void in
sender.transform = CGAffineTransform(rotationAngle: 0.0)
}, completion: nil)
Ramin で指定されたコードは正常に機能しますが、タブバーアプリケーションを使用して次のタブ項目に移動し、前のタブ項目に戻ると、ビューがすべて左に移動していることがわかりますしたがって、ベストプラクティスは、ViewWillAppearメソッドを使用することです。
- (void)viewWillAppear:(BOOL)animated
{
UIView* item = self.view;
item.transform = CGAffineTransformIdentity;
}
ビューがロードされるたびに、適切な場所でアニメーションが見つかります。このメソッドも使用します。
[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];
Swift 4+でこれを行う最も簡単な方法:
static func wobbleAnimation(button: UIButton) {
CATransaction.begin()
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.autoreverses = true
rotateAnimation.repeatCount = Float.greatestFiniteMagnitude
rotateAnimation.fromValue = CGFloat(-0.2)
rotateAnimation.toValue = CGFloat(0.2)
rotateAnimation.duration = 0.20
button.layer.add(rotateAnimation, forKey: nil)
CATransaction.commit()
}
static func stopWobbleAnimation(button: UIButton) {
button.layer.removeAllAnimations()
}
Swift
func startWiggling() {
deleteButton.isHidden = false
guard contentView.layer.animation(forKey: "wiggle") == nil else { return }
guard contentView.layer.animation(forKey: "bounce") == nil else { return }
let angle = 0.04
let wiggle = CAKeyframeAnimation(keyPath: "transform.rotation.z")
wiggle.values = [-angle, angle]
wiggle.autoreverses = true
wiggle.duration = randomInterval(0.1, variance: 0.025)
wiggle.repeatCount = Float.infinity
contentView.layer.add(wiggle, forKey: "wiggle")
let bounce = CAKeyframeAnimation(keyPath: "transform.translation.y")
bounce.values = [4.0, 0.0]
bounce.autoreverses = true
bounce.duration = randomInterval(0.12, variance: 0.025)
bounce.repeatCount = Float.infinity
contentView.layer.add(bounce, forKey: "bounce")
}
func stopWiggling() {
deleteButton.isHidden = true
contentView.layer.removeAllAnimations()
}