如何在Swift中按顺序为一系列图像视图设置动画?

时间:2019-04-06 17:24:22

标签: ios swift animation uiviewpropertyanimator

一段时间以来,我一直试图弄清楚这一点,但无济于事。基本上,我有一个UIImageViews数组,我想按顺序对动画进行1-by-1动画处理。现在,它们都正确但同时进行了动画处理。另外,我希望底部的代码仅在所有动画完成后才执行,因为现在看来好像同时执行了。我是新手,所以我想我不完全了解 for 循环的工作原理吗?在我看来,这段代码应该遍历数组中的所有图像视图,只有完成后才应在底部执行代码。在循环的每次迭代中都应调用highlightCards方法,但这似乎并没有发生。我知道随着正确图像的移动,阵列可以正确启动。

代码如下:

playedCards 是带有卡片索引的整数数组

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 个答案:

答案 0 :(得分:1)

您在正确的轨道上!唯一的问题是动画函数异步运行 -这意味着它不会等到前一个动画完成后再进入下一个循环。

您已经成为使用completion闭包的一部分。但是,如果要在上一个 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)
    })
}

编辑:我没看到您需要在整个过程完成后运行“下一转”代码。我已经更新了上面的代码,其中包含一个完成处理程序,该处理程序会在从屏幕上删除所有卡后触发。