2015-09-08 15 views
6

Ho un pulsante che chiama un codice animateWithDuration che dissolve un'immagine, dissolve il testo & in un nuovo colore bg e poi si ripristina alla normalità. L'animazione richiede alcuni secondi per essere completata e funziona alla grande.Chiamate di animazione consecutiva non funzionanti

Tuttavia! Si è verificato un problema:

A volte questo pulsante verrà nuovamente premuto prima che l'animazione termini. Quando ciò accade, voglio che l'animazione corrente si fermi e ricomincia da capo.

Ricercato soluzione non funziona

Secondo la mia lettura, la soluzione deve essere semplice, basta importare QuartzCore e aggiungere:

button.layer.removeAllAnimations() 

Questo non rimuovere l'animazione, ma la nuova seconda animazione/è totalmente incasinato. L'immagine che dovrebbe essere nascosta non lo è, il testo non compare mai e la transizione del colore è completamente sbagliata. Cosa sta succedendo!?!

//Animate Finished feedback in footer bar 
func animateFinished(textToDisplay: String, footerBtn: UIButton, footerImg: UIImageView) { 

    //Should cancel any current animation 
    footerBtn.layer.removeAllAnimations() 

    footerBtn.alpha = 0 
    footerBtn.setTitle(textToDisplay, forState: UIControlState.Normal) 
    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Regular", size: 18) 
    footerBtn.setTitleColor(UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0), forState: UIControlState.Normal) 
    footerBtn.backgroundColor = UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0) 

    UIView.animateWithDuration(0.5, delay: 0.0, options: nil, animations: { 
     footerImg.alpha = 0.01 //Img fades out 
     footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 163/255.0, blue: 00/255.0, alpha: 0.6) 
     } 
     , completion: { finished in 

      UIView.animateWithDuration(0.5, delay: 0.0, options: nil, animations: { 
       footerBtn.alpha = 1 //Text fades in 
       footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 208/255.0, blue: 11/255.0, alpha: 0.6) 
       } 
       , completion: { finished in 

        UIView.animateWithDuration(0.5, delay: 1.0, options: nil, animations: { 
         footerBtn.alpha = 0.01 //Text fades out 
         footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 173/255.0, blue: 00/255.0, alpha: 0.6) 
         } 
         , completion: { finished in 

          UIView.animateWithDuration(0.5, delay: 0.0, options: nil, animations: { 
           footerImg.alpha = 1 //Img fades in 
           } 
           , completion: { finished in 
            footerBtn.backgroundColor = UIColor.clearColor() 
            footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal) 
            footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18) 
            footerBtn.setTitle("", forState: UIControlState.Normal) 
            footerBtn.alpha = 1 
            //Completion blocks sets values back to norm 
          }) 
        }) 
      }) 
    }) 
}//End of animation 

@Shripada suggerisco di passare ai fotogrammi chiave per un codice più leggibile. Formato keyframe di seguito. Non ha risolto il problema di interruzione dell'animazione. Se è possibile risolvere il problema in formato nidificato o fotogramma chiave, si prega di postarlo!

func animateFinished(textToDisplay: String, footerBtn: UIButton, footerImg: UIImageView) { 
    //Should cancel any current animation 
    footerBtn.layer.removeAllAnimations() 

    footerBtn.alpha = 0 
    footerBtn.setTitle(textToDisplay, forState: UIControlState.Normal) 
    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Regular", size: 18) 
    footerBtn.setTitleColor(UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0), forState: UIControlState.Normal) 
    //footerBtn.backgroundColor = UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0) 

    UIView.animateKeyframesWithDuration(3.0 /*Total*/, delay:0.0, options: UIViewKeyframeAnimationOptions.CalculationModeLinear, animations: { 

      UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration:0.10, animations:{ 
       footerImg.alpha = 0.01 //Img fades out 
       footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 103/255.0, blue: 00/255.0, alpha: 0.6) //Bg turns to green 
      }) 

      UIView.addKeyframeWithRelativeStartTime(0.10, relativeDuration:0.30, animations:{ 
       footerBtn.alpha = 1 //Text and green bg fades in 
       footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 173/255.0, blue: 11/255.0, alpha: 0.6) //BG turns greener 
      }) 

      UIView.addKeyframeWithRelativeStartTime(0.40, relativeDuration:0.50, animations:{ 
       footerBtn.alpha = 0.01 //Text fades out & bg fade out 
      }) 

     }, 
     completion: { finished in 
      footerImg.alpha = 1 
      footerBtn.alpha = 1 
      footerBtn.backgroundColor = UIColor.clearColor() 
      footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal) 
      footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18) 
      footerBtn.setTitle("", forState: UIControlState.Normal) 
      //Completion blocks sets values back to norm 
     } 
    ) 
}//End of 'Finished' animation 

risposta

2

ho aggiunto alcune print righe al tuo metodo animateFinished, per vedere cosa sta succedendo:

func animateFinished(textToDisplay: String, footerBtn: UIButton, footerImg: UIImageView) { 
    //Should cancel any current animation 
    print("Remove animations") 
    footerBtn.layer.removeAllAnimations() 
    print("Animations removed") 

    footerBtn.alpha = 0 
    footerBtn.setTitle(textToDisplay, forState: UIControlState.Normal) 
    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Regular", size: 18) 
    footerBtn.setTitleColor(UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0), forState: UIControlState.Normal) 
    //footerBtn.backgroundColor = UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0) 
    print("Initial animation setup completed") 

    UIView.animateKeyframesWithDuration(3.0 /*Total*/, delay:0.0, options: UIViewKeyframeAnimationOptions.CalculationModeLinear, animations: { 

      UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration:0.10, animations:{ 
       footerImg.alpha = 0.01 //Img fades out 
       footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 103/255.0, blue: 00/255.0, alpha: 0.6) //Bg turns to green 
      }) 

      UIView.addKeyframeWithRelativeStartTime(0.10, relativeDuration:0.30, animations:{ 
       footerBtn.alpha = 1 //Text and green bg fades in 
       footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 173/255.0, blue: 11/255.0, alpha: 0.6) //BG turns greener 
      }) 

      UIView.addKeyframeWithRelativeStartTime(0.40, relativeDuration:0.50, animations:{ 
       footerBtn.alpha = 0.01 //Text fades out & bg fade out 
      }) 

     }, 
     completion: { finished in 
      print("Completion block started") 
      footerImg.alpha = 1 
      footerBtn.alpha = 1 
      footerBtn.backgroundColor = UIColor.clearColor() 
      footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal) 
      footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18) 
      footerBtn.setTitle("", forState: UIControlState.Normal) 
      //Completion blocks sets values back to norm 
      print("Completion block finished") 
     } 
    ) 
}//End of 'Finished' animation 

Se permettete che le animazioni di correre a compimento, gli spettacoli di registro, come ci si aspetterebbe:

Remove animations 
Animations removed 
Initial animation setup completed 
Completion block started 
Completion block finished 

Ma se si tocca il pulsante durante l'animazione, si vede questo:

Remove animations 
Animations removed 
Initial animation setup completed 
Remove animations 
Animations removed 
Initial animation setup completed 
Completion block started 
Completion block finished 
Completion block started 
Completion block finished 

Quello che sta succedendo è che il removeAllAnimations provoca il blocco di completamento (per la prima chiamata) da eseguire, dopo la configurazione iniziale per la seconda chiamata è terminata, ma prima il secondo animazioni sono intraprese. Ad esempio, il titolo del pulsante è "" durante la seconda animazione.

La correzione è relativamente semplice: non eseguire il blocco di completamento se le animazioni non hanno ancora terminato:

 completion: { finished in 
      if (!finished) { 
       return 
      } 
      print("Completion block started") 
      footerImg.alpha = 1 
      footerBtn.alpha = 1 
      footerBtn.backgroundColor = UIColor.clearColor() 
      footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal) 
      footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18) 
      footerBtn.setTitle("", forState: UIControlState.Normal) 
      print("Completion block finished") 
      //Completion blocks sets values back to norm 
     } 

Inoltre, come per Shripada, è necessario rimuovere le animazioni da footerImg così come footerBtn , con:

footerImg.layer.removeAllAnimations() 

all'inizio del metodo.

+0

Quindi ... non so ... sei il mio eroe. Ha funzionato come un fascino. Ho incollato quelle tre linee ed era come per magia. Sei un eroe dei mago. Grazie! –

2

È consigliabile evitare il sequenziamento delle animazioni in questo tipo di nidificazione utilizzando i blocchi di completamento delle animazioni successive. Ciò non solo lo rende altamente illeggibile, ma rende anche difficile comprendere e risolvere problemi come quello che stai menzionando.

C'è un'alternativa molto migliore, chiamata animazioni di fotogrammi chiave, e dovresti considerare di usarla (disponibile da iOS 7 in poi).

animateKeyFramesWithDuration:delay:options:animation:completion 

consultare documentation

Il vostro codice di animazione può essere riscritta utilizzando i fotogrammi chiave (PS: non ho testare questo, semplicemente scrivendo per il vostro ref) -

func animateFinished(textToDisplay: String, footerBtn: UIButton, footerImg: UIImageView) { 
    //Should cancel any current animation 
    footerBtn.layer.removeAllAnimations() 
    footerImg.layer.removeAllAnimations() 
    footerBtn.alpha = 0 
    footerBtn.setTitle(textToDisplay, forState: UIControlState.Normal) 
    footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Regular", size: 18) 
    footerBtn.setTitleColor(UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0), forState: UIControlState.Normal) 
    //footerBtn.backgroundColor = UIColor(red: 217/255.0, green: 217/255.0, blue: 217/255.0, alpha: 1.0) 

    UIView.animateKeyframesWithDuration(3.0 /*Total*/, delay:0.0, options: UIViewKeyframeAnimationOptions.CalculationModeLinear, animations: { 

      UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration:0.10, animations:{ 
       footerImg.alpha = 0.01 //Img fades out 
       footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 103/255.0, blue: 00/255.0, alpha: 0.6) //Bg turns to green 
      }) 

      UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration:0.30, animations:{ 
       footerBtn.alpha = 1 //Text and green bg fades in 
       footerBtn.backgroundColor = UIColor(red: 46/255.0, green: 173/255.0, blue: 11/255.0, alpha: 0.6) //BG turns greener 
      }) 

      UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration:0.50, animations:{ 
       footerBtn.alpha = 0.01 //Text fades out & bg fade out 
      }) 

     }, 
     completion: { finished in 
      footerImg.alpha = 1 
      footerBtn.alpha = 1 
      footerBtn.backgroundColor = UIColor.clearColor() 
      footerBtn.setTitleColor(UIColor(red: 55/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0), forState: UIControlState.Normal) 
      footerBtn.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 18) 
      footerBtn.setTitle("", forState: UIControlState.Normal) 
      //Completion blocks sets values back to norm 
     } 
    ) 
}//End of 'Finished' animation 

consultare anche questo link se è obj c, molto informativo. http://www.raizlabs.com/dev/2015/01/uiview-animation-sequencing-and-grouping-techniques/

+0

Ehi, grazie per la risposta. Questo risolverà il mio problema? Alla fine lo farò in entrambi i casi, se è il modo più pulito/più leggibile di fare le cose ... ma solo curioso perché non hai menzionato dove si trovava il problema o in che modo lo avrebbe risolto. Grazie per il chiarimento –

+0

Dovrai provare questo, questa soluzione è più pulita e hai un'animazione di fotogrammi chiave qui che una sequenza di essi. Questo probabilmente dovrebbe risolvere il tuo problema. Provaci. – Shripada

+0

Ho seguito il tuo consiglio e ho implementato il metodo dei fotogrammi chiave. Sto aggiornando la mia risposta con il nuovo codice. Le chiamate consecutive sembrano funzionare meglio. Tuttavia, il tuo codice aveva alcuni errori (due opzioni, le virgole mancanti e l'animazione era completamente fuori servizio). Se aggiorni il tuo codice, posso contrassegnarlo come corretto. Sono costretto a mantenere l'animazione finale di footerImg.alpha = 1 fino al blocco di completamento. Se lo aggiungo come fotogramma chiave finale, non svanisce mai e inizia a svanire in avanti in anticipo. Inoltre, anche se il mio tempo relativo si aggiunge a 1, c'è un intervallo di 1-2 secondi prima del blocco di completamento? –