ios - 取消一個UIView動畫?


是否有可能在進行中取消UIView動畫? 或者我將不得不下降到CA級別?

即我做了這樣的事情(也許設置結束動畫行動):

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
// other animation properties

// set view properties

[UIView commitAnimations];

但在動畫完成之前,我得到動畫結束事件,我想取消它(縮短)。 這可能嗎? 用谷歌搜索發現有幾個人問同樣的問題沒有答案 - 一兩個人猜測這是不能做的。


Answers



我這樣做的方法是為您的終點創建一個新的動畫。 設置一個非常短的時間,並確保使用+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];



最簡單的方法就是立即停止某個特定視圖上的所有動畫:

將項目鏈接到QuartzCore.framework。 在你的代碼的開始:

#import <QuartzCore/QuartzCore.h>

現在,當你想停止視圖上的所有動畫時,請說:

[CATransaction begin];
[theView.layer removeAllAnimations];
[CATransaction commit];

中線會自行工作,但是直到runloop結束(“重繪時刻”)才會有延遲。 為了防止延遲,請將命令封裝在顯式事務處理塊中,如圖所示。 這個工作提供了沒有其他的變化已經在這個層在當前的runloop執行。




在iOS 4及更高版本上, 使用第二個動畫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 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動畫立即設置屬性,然後動畫。 它在表示層匹配模型(set屬性)時停止動畫。

我解決了我的問題,那就是“我想從你看起來像你出現的地方開始動畫”(“你”的意思)。 如果你想要的話,那麼:

  1. 添加QuartzCore。
  2. CALayer * pLayer = theView.layer.presentationLayer;

將該位置設置為表示層

我使用了幾個選項,包括UIViewAnimationOptionOverrideInheritedDuration

但是,由於蘋果的文檔是模糊的,我不知道它是否真的覆蓋了其他動畫使用時,或者只是重置定時器。

[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];



我也有同樣的問題; 這些API沒有任何東西可以取消某些特定的動畫。 該

+ (void)setAnimationsEnabled:(BOOL)enabled

禁用所有的動畫,因此不適合我。 有兩個解決方案:

1)讓你的動畫對象成為子視圖。 然後,當您要取消該視圖的動畫時,請移除視圖或將其隱藏。 非常簡單,但是如果需要保持在視圖中,則需要重新創建沒有動畫的子視圖。

2)重複動畫只有一個,並作出一個委託選擇器重新啟動動畫,如果需要,如下所示:

-(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)的問題是,在完成當前動畫循環時總會有延遲停止動畫。

希望這可以幫助。




對不起復活這個答案,但在iOS 10的東西有點改變,現在取消是可能的,你甚至可以取消優雅!

在iOS 10之後,您可以使用UIViewPropertyAnimator取消動畫!

UIViewPropertyAnimator(duration: 2, dampingRatio: 0.4, animations: {
    view.backgroundColor = .blue
})
animator.stopAnimation(true)

如果通過,則取消動畫,並在取消動畫的位置停止。 完成方法不會被調用。 但是,如果您通過false,您將負責完成動畫:

animator.finishAnimation(.start)

你可以完成你的動畫並保持當前狀態(.current)或者進入初始狀態(.start)或者結束狀態(.end)

順便說一句,你甚至可以暫停,然後重新啟動...

animator.pauseAnimation()
animator.startAnimation()

注意:如果你不想突然取消,你可以改變你的動畫,甚至在暫停之後改變你的動畫!




即使您以上述方式取消動畫didStopSelector仍然運行。 所以,如果你的應用程序在由動畫驅動的邏輯狀態,你將有問題。 由於這個原因,我使用上面描述的方法使用UIView動畫的上下文變量。 如果您通過上下文參數將當前的程序狀態傳遞給動畫,那麼當動畫停止時, didStopSelector函數可以決定是否應該執行某些操作,或者僅基於當前狀態和作為上下文傳遞的狀態值來返回。




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;