2013-03-22 15 views
8

Jestem zbudować aplikację iOS, w której mam wymaganie background.Color widoku do animacji poprzez wybór kolorów. W mojej metodzieDidLoad zasadniczo rozpalam łańcuch animacji UIView używając następujących.Najlepszy sposób na obsługę łańcucha animacji za pomocą UIViewAnimations

-(void) beginFirstStageBackgroundAnimation 
{ 
    [UIView animateWithDuration: 3.0f 
          delay: 3.0f 
         options: UIViewAnimationOptionTransitionCrossDissolve 
        animations:^{ 
         self.view.backgroundColor = [UIColor colorWithRed: 251./255 green:203./255 blue:147./255 alpha:1.0]; 
        } 
        completion:^(BOOL finished){ 
         [self secondStageBackgroundAnimation]; 
        } 
    ]; 
} 

Handler ukończenie odpala drugą metodę zawierającą kolejny kolor ....

-(void) secondStageBackgroundAnimation 
{ 
    [UIView animateWithDuration: 3.0f 
          delay: 3.0f 
         options: UIViewAnimationOptionTransitionCrossDissolve 
        animations:^{ 
         self.view.backgroundColor = [UIColor colorWithRed:251./255 green:224./255 blue:96./255 alpha:1.0]; 
        } 
        completion:^(BOOL finished){ 
         [self thirdStageBackgroundAnimation]; 
        } 
    ]; 
} 

I tak dalej ... to idzie dalej, aż w siódmym animacji nazywam [self beginFirstStageBackgroundAnimation]; w celu zakończenia rozpocznij ponownie proces.

Po opuszczeniu widoku za pomocą przycisku Wstecz, w widokuDidDisappear lub gdy timer na wyświetlaczu się kończy, uruchamiam [self.view.layer removeAllAnimations];, aby całkowicie pozbyć się animacji. Jednak aplikacja działa i działa dokładnie zgodnie z przeznaczeniem, ale wydaje się, że po przełączeniu się z widoku i uruchomieniu na całość wygląda na awarię i chociaż nie wiem dlaczego, wydaje się być związana z tym łańcuchem animacji.

Czy istnieje lepsze rozwiązanie do animowania tła tła widoku co 3 sekundy z 3-sekundowym opóźnieniem?

A czy [self.view.layer removeAllAnimations]; faktycznie robi to, co chcę?

EDIT: Kod gdzie mogę zostawić pogląd jest następujący:

-(void) backBtnPressed:(id)sender 
{ 
    [self stopAudio]; // stop audio that is playing. 
    [self.view.layer removeAllAnimations]; // remove all animations? 
    [self.navigationController popViewControllerAnimated: YES]; // pop view from stack 
} 
+0

nie jestem pewien, że removeAllAnimations zatrzymuje animację, to dla animacji dołączonej do warstwy, a nie są bezpośrednio za pomocą animacji warstwy, ale animacja UIView ... i tak nie powinien upaść, można to nazwać nawet bez wywoływania żadnej animacji. jaki jest twój dziennik po awarii? – meronix

+1

+1 Prawdziwym niebezpieczeństwem tutaj jest zwijanie stosu w pętlę co trzy sekundy - w zasadzie duża powolna rekursja. odpowiedź, którą zaakceptowałeś, unika tego, podobnie jak moja własna. Jestem pewna, że ​​zaakceptowana odpowiedź jest w porządku, chociaż wolę trzymać się bloków, gdzie tylko to możliwe. – danh

Odpowiedz

5

Można spróbować użyć CAAnimation Myślę, że łatwiej będzie zarządzać kolory i animacje

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 
    NSArray *colors = @[[UIColor greenColor], 
         [UIColor redColor], 
         [UIColor blueColor], 
         [UIColor yellowColor], 
         [UIColor orangeColor] 
         ]; 
    NSMutableArray *animations = [NSMutableArray new]; 
    float colorAnimationDuration = 3.0f; 
    for (int i = 0; i < colors.count; i++) 
    { 
     CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; 
     animation.toValue = (id)[[colors objectAtIndex:i] CGColor]; 
     animation.duration = colorAnimationDuration; 
     animation.beginTime = i * colorAnimationDuration; 
     animation.removedOnCompletion = NO; 
     animation.fillMode = kCAFillModeForwards; 

     [animations addObject:animation]; 
    } 

    CAAnimationGroup *animationsGroup = [CAAnimationGroup new]; 
    animationsGroup.duration = colors.count * colorAnimationDuration; 
    animationsGroup.repeatCount = HUGE_VALF; 
    animationsGroup.animations = animations; 

    [self.view.layer addAnimation:animationsGroup forKey:@"myAnimations"]; 

} 

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
    [self.view.layer removeAnimationForKey:@"myAnimations"]; 
} 
+0

Wydaje się działać doskonale. Doceniam to: –

-1

Spróbuj dodać czek wewnątrz każdej metody animacji, jak to:

-(void) secondStageBackgroundAnimation 
{ 
if (self.view.superview){ 
    [UIView animateWithDuration: 3.0f 
          delay: 3.0f 
         options: UIViewAnimationOptionTransitionCrossDissolve 
        animations:^{ 
         self.view.backgroundColor = [UIColor colorWithRed:251./255 green:224./255 blue:96./255 alpha:1.0]; 
        } 
        completion:^(BOOL finished){ 
         [self thirdStageBackgroundAnimation]; 
        } 
    ]; 
} 
} 

można dodawać do kodu, w którym "opuszczasz widok za pomocą przycisku wstecz"? problem może być tam ...

+0

Pytanie edytowane. Kod opublikowany zgodnie z zamówieniem –

7

Myślę, że droga jest do reprezentowania, co chcesz w każdej animacji występuje parametrycznie (co w tym przypadku jest tylko kolorem), a następnie przechowuje te parametry w tablicy. Tablica jest jak lista zadań do animacji:

@property(strong, nonatomic) NSArray *animationTodo; 

Musimy również śledzić, gdzie jesteśmy na liście. Użyj pudełkową (NS) numer więc możemy reprezentować „nie animować” jako zero, różną od zera indeks:

@property(strong, nonatomic) NSNumber *animationIndex; 

Tablica jest inicjowane z kolorami:

self.animationTodo = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], ... nil]; 

teraz animacji mogą być skompresowane do jednej metody:

- (void)animate { 

    if (!animationIndex) return; 
    NSInteger index = [animationIndex intValue]; 
    [UIView animateWithDuration:3.0 animations:^{ 
     self.view.backgroundColor = [animationToDo objectAtIndex:index]; 
    } completion:^(BOOL finished) { 
     NSInteger nextIndex = (index==self.animationTodo.count-1)? 0 : index+1; // advance index in a ring 
     self.animationIndex = [NSNumber numberWithInt:nextIndex]; 
     // schedule the next one in 3s 
     [self performSelector:@selector(animate) withObject:nil afterDelay:3.0]; 
    }]; 
} 

Wykonaj selektor pozwala ci podać opóźnienie, a także ma pozytywny wpływ nie zwijania stosu przy każdym uruchomieniu kolejnej animacji.

Zatrzymanie jest teraz proste. Wykonaj tę czynność, zanim widok zniknie i kiedy indziej chcesz przestać.

- (void)stopAnimating { 

    self.animationIndex = nil; 
    [NSObject cancelPreviousPerformRequestsWithTarget:self]; 
} 
+1

Po prostu widziałem tę odpowiedź. Poszedłem z rozwiązaniem z zaakceptowanej odpowiedzi, która działa idealnie na moje potrzeby. Jest to jednak także świetny sposób, a nie coś, co nawet rozważałem. –

Powiązane problemy