【问题标题】:How do you sequentially animate an array of image views in Swift?如何在 Swift 中按顺序对一组图像视图进行动画处理?
【发布时间】:2019-04-06 17:24:21
【问题描述】:

我一直试图弄清楚这一点,但无济于事。基本上,我有一个 UIImageViews 数组,我想按顺序对它们进行 1×1 动画处理。现在,它们都正确但同时进行动画处理。此外,我希望底部的代码仅在所有动画完成后执行,因为现在它似乎是同时执行的。我对 swift 很陌生,所以我想我不完全理解 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()

【问题讨论】:

    标签: ios swift animation uiviewpropertyanimator


    【解决方案1】:

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

    您已经参与了使用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)
        })
    }
    

    编辑:我没有看到你需要在整个事情完成之后运行“下一回合”代码。我已经更新了上面的代码以包含一个完成处理程序,该处理程序会在所有卡片从屏幕上移除后触发。

    【讨论】:

    • 非常感谢!这对我来说非常有效。我错过了动画师一次触发所有线程的知识。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-17
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    相关资源
    最近更新 更多