UIView एनीमेशन रद्द करें?


244

क्या UIViewप्रगति के दौरान एनीमेशन को रद्द करना संभव है ? या मुझे सीए स्तर तक छोड़ना होगा?

यानी मैंने कुछ इस तरह किया है (शायद एक अंत एनीमेशन कार्रवाई भी स्थापित करना):

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

// set view properties

[UIView commitAnimations];

लेकिन एनीमेशन के पूरा होने से पहले और मुझे एनीमेशन समाप्त होने वाली घटना मिलती है, मैं इसे रद्द करना चाहता हूं (इसे छोटा काटें)। क्या यह संभव है? आसपास घूमने से कुछ लोगों को एक ही सवाल का जवाब नहीं मिलता है - और एक या दो लोग यह अनुमान लगा रहे हैं कि यह नहीं किया जा सकता है।


क्या आपका मतलब है एनीमेशन को बीच में रोकना और उसे वहीं छोड़ देना? या जहां यह शुरुआत में था वहां वापस जा रहा है?
क्रिस लुंडी

2
या तो इसे ठीक उसी जगह छोड़ना जहां यह है, मध्य-एनीमेशन (व्यवहार में मैं किसी भी तरह से एक और एनीमेशन सीधे शुरू करूंगा), या सीधे अंतिम बिंदु पर कूदूंगा। मैं कल्पना करूंगा कि पहला अधिक प्राकृतिक है, लेकिन इस मामले में मेरे लिए या तो काम करता है।
10

3
@ क्रिस हैसन: मैं आपके संपादन की सराहना करता हूं, लेकिन आश्चर्य है कि iPhone टैग को हटाने के लिए आपका औचित्य क्या है। यह कोको-टच द्वारा निहित हो सकता है, लेकिन मैं एक के लिए iPhone पर एक टैग फ़िल्टर कर सकता हूं और उस मामले में इसे याद करूंगा।
10

@ ब्यूट टू द हेड (फिर से): आपका सवाल, और इस पर मेरी खुद की प्रतिक्रिया ने मुझे अलगाव में परीक्षण करने के लिए प्रेरित किया और मुझे पता चला कि यदि आपने पहले एक नया एनीमेशन शुरू किया है, तो इससे पहले कि वह समाप्त हो जाए, वह अंत तक कूद जाए नई शुरुआत करने से पहले।
philsquared

- यह मेरी तात्कालिक जरूरतों को पूरा करता है (और सुझाव देता है कि मेरे वास्तविक कोड में कुछ अन्य बग हैं), लेकिन मैं इस प्रश्न को खुला छोड़ देने वाला हूं क्योंकि मुझे पता है कि अन्य लोग भी उसी के लिए पूछ रहे हैं।
philsquared

जवाबों:


114

जिस तरह से मैं करता हूं वह आपके अंतिम बिंदु पर एक नया एनीमेशन बनाना है। बहुत छोटी अवधि निर्धारित करें और सुनिश्चित करें कि आप +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];

धन्यवाद स्टीफन। वास्तव में अगर तुम मेरे सवाल के तहत टिप्पणी पढ़ने के इस ठीक है कि मैं क्या अंत में क्या किया - लेकिन जब से तुम यहाँ एक अच्छा, स्पष्ट, यह के कारण दिया है मैं के रूप में यह अंकन कर रहा हूँ स्वीकार किए जाते हैं
philsquared

1
@Vojto ऐसा कैसे? डॉक्स का कहना है कि setAnimationBeginsFromCurrentState:आईओएस 4 से हतोत्साहित किया जाता है लेकिन यह अभी भी है और अभी भी कार्य करना चाहिए।
स्टीफन डार्लिंगटन

55
iOS4 + में, UIViewAnimationOptionBeginFromCurrentState विकल्प का उपयोग चेतन पर करेंअनुकूलित करें: विलंब: विकल्प: एनिमेशन: पूरा:
एडम एबेरबेक

क्या UIViewAnimationOptionBeginFromCurrentState प्रगति में किसी भी एनीमेशन को रद्द कर देगा या केवल एक एनीमेशन जो समान संपत्ति को लक्षित करता है? यदि यह कोई एनीमेशन है, तो आप उसी एनीमेशन पर प्रगति में समान एनीमेशन को रोकने के बिना एक नया एनीमेशन कैसे जारी रख सकते हैं?
zakdances

1
@yourfriendzak, एक संक्षिप्त परीक्षण के आधार पर, ऐसा लगता है कि यह केवल उसी संपत्ति को लक्षित करने वाले एनीमेशन को रद्द करता है। मैंने स्क्रॉलव्यू के अल्फा को बदलने की कोशिश की, जिसका contentOffset एनिमेटेड था और contentOffset एनीमेशन जारी रहा।
अर्लोमेडिया

360

उपयोग:

#import <QuartzCore/QuartzCore.h>

.......

[myView.layer removeAllAnimations];

22
मैंने पाया कि मुझे एक कंपाइलर चेतावनी को हटाने के लिए #import <QuartzCore / QuartzCore.h> को जोड़ना पड़ा ;)
deanWombourne

4
इतना आसान है, और अभी तक इतना मुश्किल है। इसके लिए धन्यवाद, मैंने इसे जानने के लिए सिर्फ एक घंटे का समय दिया है।
मिकीयर्ड

4
इस समाधान के साथ संभावित समस्या यह है कि (आईओएस 5 में कम से कम) प्रभावी होने से पहले एक देरी है - यह जल्द ही काम नहीं करता है अगर आपका क्या मतलब है "अभी एनीमेशन बंद करो, इससे पहले कि मैं अगली पंक्ति पर जाऊं कोड "।
मटका

14
मैंने पाया कि यह कॉल पूरा होने को ट्रिगर करता है: ^ (BOOL समाप्त) ब्लॉक का उपयोग करते हुए + (शून्य) चेतनता अवधि: (NSTimeInterval) अवधि एनिमेशन: (शून्य (^) (शून्य)) एनिमेशन पूर्णता (शून्य (^) (BOOL समाप्त)) ) पूरा होने पर
JWGS

1
@matt क्या आपको एक समाधान पता है जो एनीमेशन को तुरंत बंद कर देता है? मैं एनीमेशन को रोकने से पहले एक छोटी सी देरी का भी अवलोकन कर रहा हूं।
tiguero

62

किसी विशेष दृश्य पर सभी एनिमेशन को रोकने का सबसे सरल तरीका , तुरंत यह है:

प्रोजेक्ट को QuartzCore.framework से लिंक करें। आपके कोड की शुरुआत में:

#import <QuartzCore/QuartzCore.h>

अब, जब आप उनके ट्रैक में मृत किसी दृश्य पर सभी एनिमेशन रोकना चाहते हैं, तो यह कहें:

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

मध्य रेखा सभी के द्वारा काम करेगी, लेकिन जब तक रनलूप समाप्त नहीं होता है ("रिड्रा पल")। उस देरी को रोकने के लिए, दिखाए गए अनुसार स्पष्ट लेनदेन ब्लॉक में कमांड लपेटें। यह काम करता है बशर्ते इस परत पर वर्तमान में कोई अन्य परिवर्तन नहीं किया गया हो।


2
मैं आपके कोड के बाद [कामोत्तेजना फ्लश] का उपयोग कर रहा हूं जो बहुत अच्छा काम करता है, कभी-कभी इसका कारण यह तुरंत नहीं लिखता है। लेकिन फिर भी, एक 0.1 सेकंड का प्रदर्शन मुद्दा है, उदाहरण के लिए यह उस विशेष समय के लिए पिछड़ जाता है। किसी भी काम?
सिडविन कोह

5
removeAllAnimationsएनीमेशन को उसके अंतिम फ्रेम में लाने का साइड इफेक्ट होगा, बजाय इसे रोकने के जहां यह अभी है।
इल्या

3
आम तौर पर, जब कोई एनीमेशन बंद करना चाहता है, तो वे उम्मीद करते हैं कि यह अपने वर्तमान फ्रेम में बंद हो जाएगा - न ही पहला फ्रेम और न ही आखिरी फ्रेम। पहले या आखिरी फ्रेम पर कूदने से झटकेदार गति दिखाई देगी।
इल्या

1
मैं उत्तर को फिर से निर्दिष्ट करूंगा कि यह निर्दिष्ट करने के लिए कि डिफ़ॉल्ट व्यवहार क्या है और इसे कैसे बदला जा सकता है। जाहिर है कि एनीमेशन करने वाला कोई व्यक्ति अपनी पद्धति कॉल के बाद स्क्रीन पर क्या होता है, में सक्रिय रूप से रुचि रखता है :)
इल्या

1
मैंने इसे अन्यत्र विस्तृत किया है। यह वही नहीं है जो मुझसे पूछा गया था इसलिए मैंने यहां जवाब नहीं दिया। यदि आपके पास एक और उत्तर है, तो निश्चित रूप से उत्तर के रूप में दें!
मैट

48

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

41

एक एनीमेशन को रद्द करने के लिए आपको बस उस संपत्ति को सेट करना होगा जो वर्तमान में एनिमेटेड हो रही है, UIView एनीमेशन के बाहर। यह एनीमेशन को रोक देगा जहाँ भी यह है, और UIView आपको केवल परिभाषित सेटिंग पर कूद जाएगा।


9
यह केवल आंशिक सच है। यह एनीमेशन को रोकता है, लेकिन यह इसे प्रतिनिधि विधियों को फायर करने से नहीं रोकता है, विशेष रूप से, एनीमेशनकैमलर हैंडलर, इसलिए यदि आपके पास वहां तर्क है, तो आपको समस्याएं दिखाई देंगी।
एम। रयान

33
इसके लिए 'समाप्त' तर्क -animationDidStop:finished:context:है। यदि [finished boolValue] == NO, तो आप जानते हैं कि आपका एनीमेशन किसी तरह रद्द कर दिया गया था।
निक फोर्ज

यह 7 साल पहले की बात है! ध्यान दें कि एक अजीब व्यवहार है: कहते हैं कि आप अल्फा बैक और फ्रंट को एनिमेट कर रहे हैं, और आप इसे "0 पर जाएं" बनाते हैं। एनीमेशन को बंद करने के लिए, आप अल्फा को शून्य पर सेट नहीं कर सकते हैं; आप इसे 1 पर सेट करते हैं।
फटी

26

इस उत्तर को फिर से ज़िंदा करने के लिए क्षमा करें, लेकिन iOS में 10 चीजें बदल गई हैं, और अब रद्द करना संभव है और आप सुंदर तरीके से रद्द भी कर सकते हैं!

IOS 10 के बाद आप UIViewPropertyAnimator के साथ एनिमेशन रद्द कर सकते हैं !

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

यदि आप सच पास करते हैं तो यह एनीमेशन को रद्द कर देता है और यह वहीं रुक जाता है जहां आपने इसे रद्द किया था। पूर्ण करने की विधि को नहीं कहा जाएगा। हालाँकि, यदि आप गलत पास करते हैं तो आप एनीमेशन को खत्म करने के लिए जिम्मेदार हैं:

animator.finishAnimation(.start)

आप अपना एनीमेशन समाप्त कर सकते हैं और वर्तमान स्थिति (। Current) में रह सकते हैं या प्रारंभिक स्थिति (.start) या अंतिम स्थिति (-end) पर जा सकते हैं।

वैसे, आप बाद में भी रोक सकते हैं और पुनः आरंभ कर सकते हैं ...

animator.pauseAnimation()
animator.startAnimation()

नोट: यदि आप एक अचानक रद्द नहीं करना चाहते हैं तो आप अपने एनीमेशन को उलट सकते हैं या इसे रोकने के बाद अपना एनीमेशन भी बदल सकते हैं!


2
यह निश्चित रूप से आधुनिक एनिमेशन के लिए सबसे अधिक प्रासंगिक है।
डग

10

यदि आप व्यू प्रॉपर्टी के बजाय स्थिरांक को बदलकर एक बाधा का एनीमेशन कर रहे हैं, तो अन्य तरीकों में से कोई भी 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];
}

1
इसके अलावा केवल self.constraintView.layer.removeAllAnimations()काम करता है (स्विफ्ट)
लछन

अन्य समाधानों में से किसी ने भी काम नहीं किया। धन्यवाद, इसने मेरे लिए काम किया।
स्वप्निलगरवाल


5

उपरोक्त में से किसी ने भी मेरे लिए इसे हल नहीं किया, लेकिन इससे मदद मिली: UIViewएनीमेशन तुरंत संपत्ति सेट करता है, फिर इसे एनिमेट करता है। जब प्रस्तुति परत मॉडल (सेट संपत्ति) से मेल खाती है तो यह एनीमेशन को रोकता है।

मैंने अपना मुद्दा हल कर दिया, जो "मैं चाहता हूं कि आप जहां दिखते हैं, वहां से चेतन हों" ('आप' का अर्थ है दृश्य)। यदि आप चाहते हैं, तो:

  1. क्वार्ट्जकोर जोड़ें।
  2. 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) {}];

और यह अभी के लिए एक सभ्य समाधान होना चाहिए।


5
[UIView setAnimationsEnabled:NO];
// your code here
[UIView setAnimationsEnabled:YES];

2

स्टीफन डार्लिंगटन के समाधान का स्विफ्ट संस्करण

UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(0.1)
// other animation properties

// set view properties
UIView.commitAnimations()

1

मेरी भी यही समस्या है; एपीआई के पास कुछ विशिष्ट एनीमेशन को रद्द करने के लिए कुछ भी नहीं है।

+ (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 के साथ समस्या) यह है कि एनिमेशन को रोकने में हमेशा देरी होती है क्योंकि यह वर्तमान एनीमेशन चक्र को पूरा करता है।

उम्मीद है की यह मदद करेगा।


1

भले ही आप एनीमेशन को उपरोक्त एनीमेशन के तरीकों से रद्द कर दें फिर didStopSelectorभी चलता है। इसलिए यदि आपके पास एनिमेशन द्वारा संचालित आपके एप्लिकेशन में लॉजिक स्टेट्स हैं तो आपको समस्याएं होंगी। इस कारण से ऊपर वर्णित तरीकों से मैं UIViewएनिमेशन के संदर्भ चर का उपयोग करता हूं । यदि आप अपने प्रोग्राम की वर्तमान स्थिति को संदर्भ पैराम द्वारा एनीमेशन में पास करते हैं, तो जब एनीमेशन बंद हो जाता है, तो आपका didStopSelectorफ़ंक्शन यह तय कर सकता है कि उसे कुछ करना चाहिए या केवल वर्तमान स्थिति के आधार पर लौटना चाहिए और राज्य मान संदर्भ के रूप में पारित हुआ।


NickForge ने टॉमटायलर के ऊपर दिए गए सही जवाब के नीचे की टिप्पणी में यह पूरी तरह से समझाया ...
Fattie

इस नोट के लिए बहुत बहुत धन्यवाद! मेरे पास वास्तव में ऐसी स्थिति है, जहां एक अगले एनीमेशन को निकाल दिया जाता है जब एनीमेशनडीडटॉप को बुलाया जाता है। यदि आप बस एक एनीमेशन निकालते हैं और तुरंत उसी कुंजी के लिए एक नया जोड़ते हैं तो मुझे लगता है कि यह काम नहीं करेगा। आपको प्रतीक्षा करने की आवश्यकता है, उदाहरण के लिए जब तक एनीमेशनडायस्टॉप किसी अन्य एनीमेशन, या कुछ और के लिए ट्रिगर हो। जिस एनीमेशन को अभी हटाया गया था, वह एनीमेशनडायडटॉप को और अधिक फायर नहीं करेगा।
रिकजेनसेन

0
CALayer * pLayer = self.layer.presentationLayer;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView animateWithDuration:0.001 animations:^{
    self.frame = pLayer.frame;
}];

0

मूल या अंतिम स्थिति में पुन: लाए बिना एक एनीमेशन को रोकने के लिए:

CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
myView.layer.speed = 0.0;
myView.layer.timeOffset = paused_time;

0

जब मैं UIStackViewएनीमेशन के साथ काम करता हूं , इसके अलावा removeAllAnimations()मुझे प्रारंभिक एक के लिए कुछ मूल्य निर्धारित करने की आवश्यकता होती है क्योंकि removeAllAnimations()उन्हें अप्रत्याशित स्थिति में सेट कर सकते हैं। मैं stackViewके साथ view1और view2अंदर, और एक दृश्य दिखाई देना चाहिए और एक छिपा हुआ:

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)
}

0

मेरे द्वारा दिए गए समाधानों में से किसी ने भी काम नहीं किया। मैंने अपने मुद्दों को इस तरह से हल किया (मुझे नहीं पता कि क्या यह एक सही तरीका है?), क्योंकि मुझे यह बहुत तेज कहते समय समस्याएं थीं (जब पिछले एनीमेशन अभी तक समाप्त नहीं हुआ था)। मैं 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()
                }
        })

    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.