進行中にUIView
アニメーションをキャンセルすることはできますか?または、CAレベルにドロップする必要がありますか?
すなわち、私はこのようなことをしました(おそらくアニメーション終了アクションも設定しています):
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
// other animation properties
// set view properties
[UIView commitAnimations];
しかし、アニメーションが完了し、アニメーション終了イベントを取得する前に、キャンセルします(短く切ります)。これは可能ですか?グーグルで検索すると、答えのない同じ質問をする人が数人見つかります。1人か2人がそれができないと推測します。
私がやる方法は、エンドポイントに新しいアニメーションを作成することです。非常に短い期間を設定し、+setAnimationBeginsFromCurrentState:
メソッドを使用して現在の状態から開始するようにしてください。 YESに設定すると、現在のアニメーションが短くなります。次のようになります。
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.1];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
// other animation properties
// set view properties
[UIView commitAnimations];
つかいます:
#import <QuartzCore/QuartzCore.h>
.......
[myView.layer removeAllAnimations];
all特定のビューでのアニメーションを停止する最も簡単な方法即時は、次のとおりです。
プロジェクトをQuartzCore.frameworkにリンクします。コードの開始時:
#import <QuartzCore/QuartzCore.h>
さて、トラックで死んだビューのすべてのアニメーションを停止したい場合は、次のように言います:
[CATransaction begin];
[theView.layer removeAllAnimations];
[CATransaction commit];
中央の行はすべて単独で機能しますが、実行ループが終了するまで遅延があります(「再描画の瞬間」)。その遅延を防ぐには、示されているように明示的なトランザクションブロックでコマンドをラップします。これは、現在のランループのこのレイヤーで他の変更が実行されていない場合に機能します。
IOS 4以降では、2番目のアニメーションでUIViewAnimationOptionBeginFromCurrentState
オプションを使用を使用して、最初のアニメーションを短くします。
例として、アクティビティインジケータのあるビューがあるとします。時間のかかる可能性のあるアクティビティが始まる間、アクティビティインジケータをフェードインし、アクティビティが終了するとフェードアウトします。以下のコードでは、アクティビティインジケータが表示されているビューはactivityView
と呼ばれます。
- (void)showActivityIndicator {
activityView.alpha = 0.0;
activityView.hidden = NO;
[UIView animateWithDuration:0.5
animations:^(void) {
activityView.alpha = 1.0;
}];
- (void)hideActivityIndicator {
[UIView animateWithDuration:0.5
delay:0 options:UIViewAnimationOptionBeginFromCurrentState
animations:^(void) {
activityView.alpha = 0.0;
}
completion:^(BOOL completed) {
if (completed) {
activityView.hidden = YES;
}
}];
}
アニメーションをキャンセルするには、UIViewアニメーションの外で、現在アニメーション化されているプロパティを設定するだけです。それはどこにいてもアニメーションを停止し、UIViewは先ほど定義した設定にジャンプします。
この回答を復活させて申し訳ありませんが、iOS 10では状況が少し変更され、キャンセルが可能になり、優雅にキャンセルすることさえできます!
IOS 10以降では、 IViewPropertyAnimator !でアニメーションをキャンセルできます。
UIViewPropertyAnimator(duration: 2, dampingRatio: 0.4, animations: {
view.backgroundColor = .blue
})
animator.stopAnimation(true)
Trueを渡すと、アニメーションがキャンセルされ、キャンセルした場所で停止します。完了メソッドは呼び出されません。ただし、falseを渡すと、アニメーションを終了する責任があります。
animator.finishAnimation(.start)
アニメーションを終了して現在の状態(.current)のままにするか、初期状態(.start)または終了状態(.end)に移動できます
ところで、後で一時停止して再起動することもできます...
animator.pauseAnimation()
animator.startAnimation()
注:突然のキャンセルを望まない場合は、アニメーションを逆にしたり、一時停止した後にアニメーションを変更したりできます!
ビュープロパティの代わりに定数を変更して制約をアニメートする場合、他のメソッドはiOS 8では機能しません。
アニメーションの例:
self.constraint.constant = 0;
[self.view updateConstraintsIfNeeded];
[self.view layoutIfNeeded];
[UIView animateWithDuration:1.0f
delay:0.0f
options:UIViewAnimationOptionCurveLinear
animations:^{
self.constraint.constant = 1.0f;
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
解決策:
制約の変更とそのサブレイヤーの影響を受けるビューのレイヤーからアニメーションを削除する必要があります。
[self.constraintView.layer removeAllAnimations];
for (CALayer *l in self.constraintView.layer.sublayers)
{
[l removeAllAnimations];
}
上記のどれも私のためにそれを解決しませんでしたが、これは助けました:UIView
アニメーションはすぐにプロパティを設定し、それをアニメーション化します。プレゼンテーションレイヤーがモデル(セットプロパティ)に一致すると、アニメーションを停止します。
「あなたが現れるように見える場所からアニメーション化したい」という問題を解決しました(「あなた」はビューを意味します)。あなたがそれを望むなら、それから:
CALayer * pLayer = theView.layer.presentationLayer;
プレゼンテーション層に位置を設定します
UIViewAnimationOptionOverrideInheritedDuration
を含むいくつかのオプションを使用します
しかし、Appleのドキュメントはあいまいであるため、使用時に実際に他のアニメーションをオーバーライドするのか、単にタイマーをリセットするのかはわかりません。
[UIView animateWithDuration:blah...
options: UIViewAnimationOptionBeginFromCurrentState ...
animations: ^ {
theView.center = CGPointMake( pLayer.position.x + YOUR_ANIMATION_OFFSET, pLayer.position.y + ANOTHER_ANIMATION_OFFSET);
//this only works for translating, but you get the idea if you wanna flip and scale it.
} completion: ^(BOOL complete) {}];
そして、それは今のところまともな解決策でなければなりません。
[UIView setAnimationsEnabled:NO];
// your code here
[UIView setAnimationsEnabled:YES];
スティーブンダーリントンのソリューションの迅速なバージョン
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(0.1)
// other animation properties
// set view properties
UIView.commitAnimations()
私は同じ問題を抱えています; APIには特定のアニメーションをキャンセルするものは何もありません。の
+ (void)setAnimationsEnabled:(BOOL)enabled
すべてのアニメーションを無効にし、したがって私のために動作しません。 2つの解決策があります。
1)アニメーション化されたオブジェクトをサブビューにします。次に、そのビューのアニメーションをキャンセルする場合は、ビューを削除するか非表示にします。非常に簡単ですが、ビューを維持する必要がある場合は、アニメーションなしでサブビューを再作成する必要があります。
2)アニメーションを1つだけ繰り返し、必要に応じてデリゲートセレクターを作成して、次のようにアニメーションを再起動します。
-(void) startAnimation {
NSLog(@"startAnim alpha:%f", self.alpha);
[self setAlpha:1.0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(pulseAnimationDidStop:finished:context:)];
[self setAlpha:0.1];
[UIView commitAnimations];
}
- (void)pulseAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
if(hasFocus) {
[self startAnimation];
} else {
self.alpha = 1.0;
}
}
-(void) setHasFocus:(BOOL)_hasFocus {
hasFocus = _hasFocus;
if(hasFocus) {
[self startAnimation];
}
}
2)の問題は、現在のアニメーションサイクルが完了すると、アニメーションの停止が常に遅れることです。
お役に立てれば。
CALayer * pLayer = self.layer.presentationLayer;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView animateWithDuration:0.001 animations:^{
self.frame = pLayer.frame;
}];
状態を元の状態または最終状態に戻さずにアニメーションを一時停止するには:
CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
myView.layer.speed = 0.0;
myView.layer.timeOffset = paused_time;
上記の方法でアニメーションをキャンセルしても、didStopSelector
は引き続き実行されます。そのため、アニメーションによって駆動されるアプリケーションのロジック状態がある場合、問題が発生します。このため、上記の方法では、UIView
アニメーションのコンテキスト変数を使用します。コンテキストパラメータによってアニメーションの現在の状態をアニメーションに渡す場合、アニメーションが停止すると、didStopSelector
関数は、現在の状態とコンテキストとして渡された状態値に基づいて何かを実行するか、単に返すかを決定する場合があります。
答えられたソリューションはどれも私にとってはうまくいきませんでした。この方法で問題を解決しました(正しい方法であるかどうかわかりませんか?)。これは早すぎる呼び出し(以前のアニメーションがまだ終了していない場合)で問題が発生したためです。必要なアニメーションをcustomAnimブロックで渡します。
extension UIView
{
func niceCustomTranstion(
duration: CGFloat = 0.3,
options: UIView.AnimationOptions = .transitionCrossDissolve,
customAnim: @escaping () -> Void
)
{
UIView.transition(
with: self,
duration: TimeInterval(duration),
options: options,
animations: {
customAnim()
},
completion: { (finished) in
if !finished
{
// NOTE: This fixes possible flickering ON FAST TAPPINGS
// NOTE: This fixes possible flickering ON FAST TAPPINGS
// NOTE: This fixes possible flickering ON FAST TAPPINGS
self.layer.removeAllAnimations()
customAnim()
}
})
}
}
removeAllAnimations()
以外のUIStackView
アニメーションで作業するときは、removeAllAnimations()
が予測不可能な状態に設定できるため、いくつかの値を初期値に設定する必要があります。 view1
とview2
を含むstackView
があり、1つのビューが表示され、1つのビューが非表示になっている必要があります。
public func configureStackView(hideView1: Bool, hideView2: Bool) {
let oldHideView1 = view1.isHidden
let oldHideView2 = view2.isHidden
view1.layer.removeAllAnimations()
view2.layer.removeAllAnimations()
view.layer.removeAllAnimations()
stackView.layer.removeAllAnimations()
// after stopping animation the values are unpredictable, so set values to old
view1.isHidden = oldHideView1 // <- Solution is here
view2.isHidden = oldHideView2 // <- Solution is here
UIView.animate(withDuration: 0.3,
delay: 0.0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 1,
options: [],
animations: {
view1.isHidden = hideView1
view2.isHidden = hideView2
stackView.layoutIfNeeded()
},
completion: nil)
}