2016-04-03 5 views
0

У меня есть анимация ключевого кадра, чтобы показать эффект работы с картой в Swift. Я использую вторую анимацию (используя .BeginFromCurrentState ...), чтобы отменить сделку, если вы нажмете кнопку. Это эффективно работало с простой анимацией одного вида. Однако здесь есть 2-10-секундная задержка после нажатия кнопки, по-видимому, при каждой анимации отмены. Есть ли более простой способ добиться того, что я хочу (сразу же отменив сделку).Эффективная отмена анимации ключевого кадра в Swift

Вот фрагмент кода, который устанавливает дилинговый анимации:

let durationSlice = 1.0/Double(numCards*numPlayers+1) 
    var durationSliceStart : Double = 0 
    UIView.animateKeyframesWithDuration(FiveKings.ANIMATION_250MS*(Double(numCards)*Double(numPlayers)+1), delay: 0.0 , 
     options: [.CalculationModeCubic], 
     animations: { 
      for iCard in 0..<numCards { 
       durationSliceStart = Double(iCard*numPlayers) * durationSlice 
       //translate the cards off the pile and to each mini Hand (and they stay visible) 
       for iPlayer in 0..<numPlayers { 
        //Animate the card into view at the start of this set 
        UIView.addKeyframeWithRelativeStartTime(durationSliceStart+Double(iPlayer)*durationSlice, relativeDuration: 0.0, animations: { 
          pileCardViews[iCard*numPlayers + iPlayer].alpha = 1.0 
         }) 


        //add a random amount of translation and rotation to simulate messy cards 
        let messyX = CGFloat((drand48()-0.5) * MESSY_CARD_XY_OFFSET) * self.mDrawPile.bounds.width 
        let messyY = CGFloat((drand48()-0.5) * MESSY_CARD_XY_OFFSET) * self.mDrawPile.bounds.height 
        let messyRotation = CGFloat((drand48()-0.5) * MESSY_CARD_ANGLE) * 2.0 * 3.14 

        //convert the destination miniHand into the coordinates of mDrawPile 
        let miniHandLayout = self.mGame.players.getPlayer(iPlayer).miniHandLayout! 
        miniHandDestinationPoint = miniHandLayout.cardView.convertPoint(CGPoint(x: 0,y: 0), toView: self.mDrawPile) 
        UIView.addKeyframeWithRelativeStartTime(durationSliceStart+Double(iPlayer)*durationSlice, relativeDuration: durationSlice, animations: { 
         pileCardViews[iCard*numPlayers + iPlayer].transform = CGAffineTransformConcat(
          CGAffineTransformMakeRotation(3.14+messyRotation), 
          CGAffineTransformMakeTranslation(miniHandDestinationPoint.x + messyX, miniHandDestinationPoint.y + messyY)) 
         if iCard == 0 {miniHandLayout.cardView.alpha = 1.0} 
        }) 

       } 

      }//end iCard 
      //animate a card to the DiscardPile 
      let discardPileDestination = self.mDiscardPile.convertPoint(CGPoint(x: 0, y: 0), toView: self.mDrawPile) 
      UIView.addKeyframeWithRelativeStartTime(durationSliceStart+Double(numPlayers)*durationSlice, relativeDuration: durationSlice, animations: 
       { 
        pileCardViews[numCards*numPlayers].transform = CGAffineTransformMakeTranslation(discardPileDestination.x, discardPileDestination.y) 
        pileCardViews[numCards*numPlayers].alpha = 1.0 
      }) 
     }, 
     //completion block removes the added cards 
     completion: {(_ : Bool) in 
      //remove the added cards 
      for pcv in pileCardViews {pcv.removeFromSuperview()} 
      self.afterDealing() 
     } 
    )//end UIView.animateKeyFramesWithDuration 

Вот код, который запускается при нажатии на кнопку «Пропустить дело»:

if !mDealingPileCards.isEmpty { 
     for pcv in self.mDealingPileCards {pcv.stopAnimation()} //also seems to call completion handler 
     self.mDealingPileCards.removeAll(keepCapacity: true) 
     self.setShowHint(stringKey: "toDisableDealing", setShowHint: FiveKings.HandleHint.SET_AND_SHOW_HINT, hintLevel: GameDifficulty.MEDIUM) 
    } 

и осуществление stopAnimation является расширением до UIView:

func stopAnimation() { 
    UIView.animateWithDuration(0.0, delay: 0.0, options: [.BeginFromCurrentState], 
     animations: { 
      self.alpha = 1.0 
      self.transform = CGAffineTransformIdentity 
     }, completion: nil) 
} 

EDIT: Я попытался использовать ...layer.removeAllAnimations, но возникает такая же проблема с задержкой, возможно, пока выполняется обработчик завершения?

ответ

1

Чтобы отменить анимацию, просто скажите removeAllAnimations на каждый слой (или слой каждого вида), который был анимирован. Вам также нужно будет решить, где вы сейчас хотите, чтобы это представление появилось, но это другой вопрос (другими словами, вы должны думать о том, что фактически состоит в отмене).

+0

Да, я уже пробовал это. То же самое происходит - длительная пауза продолжается, а removeAllAnimations завершается. – Opus1217

+0

«есть длинная пауза, в то время как removeAllAnimations завершает« Действительно? Вы уверены, что у вас нет проблемы с потоками? – matt

+0

В моем фрагменте кода, вышедшем выше, если я заменю pcv.stopAnimation() с помощью pcv.layer.removeAllAnimations() Я получаю тот же «застой» в пользовательском интерфейсе. Можете ли вы указать мне, что я могу сделать, чтобы отследить «проблему с потоками»? Больше ничего не происходит. – Opus1217

0

Прямой ответ на вопрос (который сам ставит другой вопрос) состоит в том, что либо stopAnimation (вызов другой анимации с использованием .BeginFromCurrentState), либо ..layer.removeAllAnimations фактически отменяет анимацию. Однако в моем случае в блоке завершения выполнялась дополнительная работа пользовательского интерфейса, которая, по-видимому, не запускается до запланированного времени. Другими словами, даже если вы отменяете/удаляете анимацию ключевых кадров отдельно, блок завершения задерживается.

Смежные вопросы