Как вы последовательно анимируете массив изображений в Swift? - PullRequest
1 голос
/ 06 апреля 2019

Я пытался понять это некоторое время, но безрезультатно. По сути, у меня есть массив UIImageViews, которые я хочу анимировать 1 на 1 по порядку. Сейчас они все оживляют правильно, но одновременно. Кроме того, я хочу, чтобы код внизу выполнялся только ПОСЛЕ того, как все анимации выполнены, так как сейчас он, кажется, выполняется одновременно. Я довольно новичок в Swift, так что, думаю, я не до конца понимаю, как работают циклы для ? На мой взгляд, этот код должен перебирать все изображения в массиве, и только после того, как он будет выполнен, он должен выполнить код внизу. метод highlightCards должен вызываться на каждой итерации цикла, но этого также не происходит. Я знаю, что массивы инициализируются правильно, так как правильные изображения перемещаются.

Вот код:

PlayCards - массив целых с карточными индексами

game.board представляет собой массив объектов карты (UIImageView)

highlightCards () просто выделяет карты, которые в настоящее время могут быть воспроизведены

Код в блоке завершения предназначен только для логистики, и я знаю, что он работает правильно

Код под комментарием «создать новую игру» должен выполняться только после завершения всех анимаций

for i in 0..<game.playedCards.count {
    // update highlights
    self.highlightCards()

    // animate cards off screen
    let endPoint: CGPoint = CGPoint(x: 1000, y: 250 )

    UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 3, delay: 2, options: UIView.AnimationOptions.curveEaseInOut, animations: {
        () -> Void in
        self.game.board[self.game.playedCards[i]].center = endPoint
    }, completion: {
        (Bool) -> Void in
        self.game.board[self.game.playedCards[i]].removed = true
        self.game.board[self.game.playedCards[i]].removeFromSuperview()
        self.currentCardCount = self.currentCardCount - 1
    })
}

// set up next turn
game.blueTurn = !game.blueTurn
self.setBackground()
self.setSuitIndicators()
self.highlightCards()

1 Ответ

1 голос
/ 06 апреля 2019

Вы на правильном пути!Единственная проблема здесь в том, что функция анимации запускается асинхронно - это означает, что она не будет ждать, пока предыдущая вещь не закончит анимацию, прежде чем перейти к следующему циклу.

Вы уже участвуете в использовании затвора completion.Однако, если вы хотите подождать, чтобы анимировать элемент next после завершение предыдущего, вам, по сути, придется найти способ снова запустить аниматор свойств изнутриБлок завершения.

Лучший способ сделать это - извлечь из функции вызов анимации вашего свойства.Тогда это становится проще!

// This is a function that contains what you've included in your code snippet.
func animateCards() {

    // update highlights
    highlightCards()

    // animate cards off screen
    let endPoint: CGPoint = CGPoint(x: 1000, y: 250)
    recursivelyAnimateCard(at: game.playedCards.startIndex, to: endPoint) {

        //set up next turn
        self.game.blueTurn = !self.game.blueTurn
        self.setBackground()
        self.setSuitIndicators()
        self.highlightCards()
    }
}

// This function replicates your for-loop that animates everything.
func recursivelyAnimateCard(at index: Int, to endPoint: CGPoint, completion: () -> Void) {

    // If this triggers, we've iterated through all of the cards. We can exit early and fire off the completion handler.
    guard game.playedCards.indices.contains(index) else {
        completion()
        return 
    }

    UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 3, delay: 2, options: UIView.AnimationOptions.curveEaseInOut, 
    animations: {
        self.game.board[self.game.playedCards[index]].center = endPoint
    }, 
    completion: { _ in
        self.game.board[self.game.playedCards[index]].removed = true
        self.game.board[self.game.playedCards[index]].removeFromSuperview()
        self.currentCardCount = self.currentCardCount - 1

        // Call this function again on completion, but for the next card.
        self.recursivelyAnimateCard(at: index + 1, to: endPoint, completion: completion)
    })
}

РЕДАКТИРОВАТЬ: я не видел вашей необходимости запуска кода «следующий ход» после все завершено.Я обновил код выше, чтобы он содержал обработчик завершения, который запускается после удаления всех карт с экрана.

...