2012-07-31 54 views
17

मुझे चेन एनिमेशन, CABasicAnimation या CAAnimationGroup की आवश्यकता है, लेकिन मुझे नहीं पता कि यह कैसे करना है, केवल यही है कि सभी एनीमेशन एक ही समय में निष्पादित होते हैं परत।आईओएस एप्लिकेशन में विभिन्न CAAnimation को कैसे चेन करें

मैं यह कैसे कर सकता हूं?

उदाहरण के लिए, एक कार छवि के लिए सेट इसकी सामग्री के साथ एक परत:

1: सही

2 करने के लिए कदम एक्स अंक: घुमाएँ 90ª छोड़ दिया करने के लिए

3: ले जाएँ एक्स बिंदु

4: परत

सभी इस एनिमेशन एक secuencial तरह से मार डाला जाना चाहिए स्केल, लेकिन मैं यह नहीं कर सकते: एस

012,

Btw: डी

+0

आप और अधिक उन्नत करने के लिए एनिमेशन के साथ-साथ या केवल आगे बढ़, स्केलिंग और (3 डी नहीं) घूर्णन का इरादा है? –

+0

हां, मैं भी CATransform3DMakeRotation और अन्य – torhector2

उत्तर

16

tl; डॉ: अगर मैं अपने व्याकरण में कुछ गलतियां मैं अंग्रेज़ी नहीं, माफी चाहता हूँ आप मैन्युअल रूप से पिछले खत्म होने के बाद प्रत्येक एनीमेशन जोड़ने की जरूरत है।


अनुक्रमिक एनिमेशन जोड़ने के लिए कोई भी तरीका नहीं बनाया गया है। आप प्रत्येक एनीमेशन की देरी को पिछले सभी एनिमेशनों का योग निर्धारित करने के लिए सेट कर सकते हैं लेकिन मैं इसकी अनुशंसा नहीं करता।

इसके बजाय मैं सभी एनिमेशन बनाउंगा और उन्हें एक म्यूटेबल सरणी (सरणी के रूप में सरणी का उपयोग करके) में क्रमबद्ध करने के क्रम में जोड़ दूंगा। फिर अपने आप को एनीमेशन के रूप में सेट करके सभी एनिमेशन में प्रतिनिधि को animationDidStop:finished: कॉलबैक प्राप्त हो सकता है जब भी कोई एनीमेशन समाप्त हो जाता है।

उस विधि में आप सरणी से पहली एनीमेशन (अगली एनीमेशन का अर्थ) हटा देंगे और इसे परत में जोड़ देंगे। चूंकि आप प्रतिनिधि हैं, इसलिए आपको दूसरी एनीमेशन मिल जाएगी जब वह एक स्थिति में animationDidStop:finished: कॉलबैक फिर से चलाएगा और अगली एनीमेशन को म्यूटेबल सरणी से हटा दिया जाएगा और परत में जोड़ा जाएगा।

एक बार एनिमेशन की सरणी खाली हो जाने पर, सभी एनिमेशन चलेंगे।


कुछ नमूना कोड शुरू करने के लिए। सबसे पहले आप अपने सभी एनिमेशन की स्थापना:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; 
[animation setToValue:(id)[[UIColor redColor] CGColor]]; 
[animation setDuration:1.5]; 
[animation setDelegate:self]; 
[animation setValue:[view layer] forKey:@"layerToApplyAnimationTo"]; 

// Configure other animations the same way ... 

[self setSequenceOfAnimations:[NSMutableArray arrayWithArray: @[ animation, animation1, animation2, animation3, animation4, animation5 ] ]]; 

// Start the chain of animations by adding the "next" (the first) animation 
[self applyNextAnimation]; 

तब प्रतिनिधि कॉलबैक में आप बस अगले एनीमेशन लागू फिर

- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished { 
    [self applyNextAnimation]; 
} 

- (void)applyNextAnimation { 
    // Finish when there are no more animations to run 
    if ([[self sequenceOfAnimations] count] == 0) return; 

    // Get the next animation and remove it from the "queue" 
    CAPropertyAnimation * nextAnimation = [[self sequenceOfAnimations] objectAtIndex:0]; 
    [[self sequenceOfAnimations] removeObjectAtIndex:0]; 

    // Get the layer and apply the animation 
    CALayer *layerToAnimate = [nextAnimation valueForKey:@"layerToApplyAnimationTo"]; 
    [layerToAnimate addAnimation:nextAnimation forKey:nil]; 
} 

मैं ताकि प्रत्येक एनीमेशन इसकी परत जानता है एक कस्टम कुंजी layerToApplyAnimationTo उपयोग कर रहा हूँ (यह केवल setValue:forKey: और valueForKey: द्वारा काम करता है)।

+0

डेविड का उपयोग करता हूं, आप कैसे प्रत्येक एनीमेशन के लिए अलग-अलग स्टार्टटाइम मान सेट करना पसंद नहीं करते हैं? समापन विधि का उपयोग करके एनिमेशन को चेन करने से कोड के लिए अक्सर आसान होता है, और यह मेरे अनुभव में पूरी तरह से काम करता है। –

+1

@ डंकनसी मुझे यह नाजुक लगता है। एनिमेशन के क्रम को जोड़ना, हटाना या बदलना अधिक बोझिल हो जाता है और त्रुटियों के लिए प्रवण होता है। –

+1

आपको बहुत धन्यवाद, मुझे लगता है कि दोनों जवाब मेरे लिए मान्य हैं, लेकिन डेविड एप्रोच मेरे लिए बेहतर दिखता है। – torhector2

28

क्या डेविड सुझाव ठीक काम करता है, लेकिन मैं एक अलग तरीके की सिफारिश करता हूं।

अपने सभी एनिमेशन एक ही परत के लिए कर रहे हैं, तो आप एक एनीमेशन समूह बना सकते हैं, और जहां पहले एनीमेशन beginTime 0 पर शुरू होता है प्रत्येक एनीमेशन एक अलग beginTime, कर, और प्रत्येक नए एनीमेशन की कुल अवधि के बाद शुरू होता है पहले एनिमेशन

यदि आपके एनिमेशन विभिन्न परतों पर हैं, हालांकि, आप एनीमेशन समूहों का उपयोग नहीं कर सकते हैं (एनीमेशन समूह में सभी एनीमेशन एक ही परत पर कार्य करना चाहिए।) उस स्थिति में, आपको अलग-अलग एनिमेशन सबमिट करने होंगे जो एक beginTime कि CACurrentMediaTime() से ऑफसेट है, है जैसे:

CGFloat totalDuration = 0; 
CABasicAnimation *animationOne = [CABasicAnimation animationWithKeyPath: @"alpha"]; 
animationOne.beginTime = CACurrentMediaTime(); //Start instantly. 
animationOne.duration = animationOneDuration; 
... 
//add animation to layer 

totalDuration += animationOneDuration; 

CABasicAnimation *animationTwo = [CABasicAnimation animationWithKeyPath: @"position"]; 
animationTwo.beginTime = CACurrentMediaTime() + totalDuration; //Start after animation one. 
animationTwo.duration = animationTwoDuration; 
... 
//add animation to layer 

totalDuration += animationTwoDuration; 


CABasicAnimation *animationThree = [CABasicAnimation animationWithKeyPath: @"position"]; 
animationThree.beginTime = CACurrentMediaTime() + totalDuration; //Start after animation three. 
animationThree.duration = animationThreeDuration; 
... 
//add animation to layer 

totalDuration += animationThreeDuration; 
+5

यदि यह किसी और की सहायता करता है: यदि आप एक एनीमेशन समूह (यानी कोड स्निपेट नहीं बल्कि डेविड के पहले अनुच्छेद) का उपयोग करते हैं, तो एनीमेशन.बेजिन टिम के सापेक्ष है समूह .... तो आप इसे CACurrentMediaTime() पर सेट नहीं करते हैं, आप इसे कुल अवधि में सेट करते हैं। यह मुझे कुछ मिनटों के लिए परेशान था .... – xaphod

1

या तो दाऊद के दृष्टिकोण या beginTime संपत्ति एनिमेशन चेनिंग के लिए ठीक हैं। http://wangling.me/2011/06/time-warp-in-animation.html देखें - यह स्टार्टटाइम और अन्य CAMediaTiming प्रोटोकॉल गुणों के उपयोग को स्पष्ट करता है।

0

केवीसी का उपयोग करें। प्रत्येक एनीमेशन के लिए कुंजी के लिए सेट करें। उसके बाद एनीमेशन DidStop में आप परिभाषित कर सकते हैं कि एनीमेशन बंद कर दिया गया है और श्रृंखला में अगला चलाया गया है।

- (void)moveXrightAnimation { 
 
    CABasicAnimation* theAnimation = ... 
 
    [theAnimation setValue:@"movexright" forKey:@"animationID"]; 
 
//animation 
 
} 
 

 
- (void)rotate90leftAnimation { 
 
    CABasicAnimation* theAnimation = ... 
 
    [theAnimation setValue:@"rotate90left" forKey:@"animationID"]; 
 
//animation 
 
} 
 

 
- (void)moveXpointAnimation { 
 
    CABasicAnimation* theAnimation = ... 
 
    [theAnimation setValue:@"movexpoint" forKey:@"animationID"]; 
 
//animation 
 
} 
 

 
- (void)scaleAnimation { 
 
    CABasicAnimation* theAnimation = ... 
 
    [theAnimation setValue:@"scale" forKey:@"animationID"]; 
 
//animation 
 
} 
 

 
#pragma mark - CAAnimationDelegate 
 

 
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 
 
    
 
    if([[anim valueForKey:@"animationID"] isEqual:@"movexright"]) { 
 
     [self rotate90leftAnimation]; 
 
    } 
 
    if([[anim valueForKey:@"animationID"] isEqual:@"rotate90left"]) { 
 
     [self moveXpointAnimation]; 
 
    } 
 
    if([[anim valueForKey:@"animationID"] isEqual:@"movexpoint"]) { 
 
     [self scaleAnimation]; 
 
    } 
 
}

1

यहाँ स्विफ्ट में एक समाधान है:

var animations = [CABasicAnimation]() 

var animation1 = CABasicAnimation(keyPath: "key_path_1") 
// animation set up here, I've included a few properties as an example 
animation1.duration = 1.0 
animation1.fromValue = 1 
animation1.toValue = 0 
animation1.append(animation1) 

var animation2 = CABasicAnimation(keyPath: "key_path_2") 
animation2.duration = 1.0 
animation2.fromValue = 1 
animation2.toValue = 0 
// setting beginTime is the key to chaining these 
animation2.beginTime = 1.0 
animations.append(animation2) 

let group = CAAnimationGroup() 
group.duration = 2.0 
group.repeatCount = FLT_MAX 
group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 
group.animations = animations 

yourLayer.addAnimation(group, forKey: nil)