CAEmitterLayer 未从视图中心发射粒子

CAEmitterLayer not emitting particles from view center

提问人:batman 提问时间:9/5/2023 更新时间:9/5/2023 访问量:40

问:

我有以下 BoardView,它包装在 UIViewRepresentable 中,并显示在 SwiftUI VStack 中。它基本上是 UIView 磁贴的 3x3 网格。我试图实现的是,当在视图上调用 showWinningAnimation 时,每个图块都应该以非常短的随机时间间隔从图块中心爆炸成五彩纸屑状粒子,向各个方向投射粒子,并且图块应该消失。爆炸应该类似于鞭炮,这是我最好的说法。我有以下代码,但似乎爆炸发生在不同的位置,而不是从每个瓷砖的中心点开始,并且投影也不像烟花。还有没有更好的方法可以使瓷砖在爆炸时消失?目前,我将 alpha 设置为 0.0,但我对结果不太满意。

class BoardView: UIView {
    private let tilesPerRow = 3
    private let tileSize = CGSize(width: 100, height: 100)
    private let tileContainerView = UIView()
    private let tileColors: [UIColor] = [.red, .blue, .orange, .yellow, .green, .white]
    
    override func layoutSubviews() {
        tileContainerView.center = self.center
    }
    
    func addTiles() {
        tileContainerView.frame = CGRect(origin: .zero, size: CGSize(width: tileSize.width * CGFloat(tilesPerRow),
                                                                     height: tileSize.height * CGFloat(tilesPerRow)))
        for row in 0..<tilesPerRow {
            for col in 0..<tilesPerRow {
                let frame = CGRect(
                    x: CGFloat(col) * tileSize.width,
                    y: CGFloat(row) * tileSize.width,
                    width: tileSize.width,
                    height: tileSize.height
                )
                let tileView = UIView(frame: frame)
                tileView.backgroundColor = tileColors.randomElement()
                tileContainerView.addSubview(tileView)
            }
        }
        addSubview(tileContainerView)
        tileContainerView.center = self.center
    }
    
    func showWinningAnimation() {
        for subview in tileContainerView.subviews {

            let confettiEmitter = CAEmitterLayer()
            confettiEmitter.emitterShape = .rectangle
            confettiEmitter.emitterPosition = subview.center
            confettiEmitter.emitterSize = subview.bounds.size

            var confettiCells = [CAEmitterCell]()
            for color in self.tileColors {
                confettiCells.append(self.confettiWithColor(color: color))
            }

            confettiEmitter.emitterCells = confettiCells
            subview.layer.addSublayer(confettiEmitter)

            UIView.animate(withDuration: .random(in: 0...1)) {
                 subview.alpha = 0
            } completion: { _ in
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    confettiEmitter.removeFromSuperlayer()
                }
            }
        }
    }

    private func confettiWithColor(color: UIColor) -> CAEmitterCell {
        let confetti = CAEmitterCell()
        confetti.color = color.cgColor
        confetti.birthRate = 5.0
        confetti.lifetime = 5.0
        confetti.velocity = 150
        confetti.emissionLongitude = CGFloat.pi
        confetti.emissionRange = CGFloat.pi * 2
        confetti.spin = 3.5
        confetti.spinRange = 1
        confetti.scaleRange = 0.5
        confetti.scaleSpeed = -0.1
        confetti.contents = UIImage.imageWithColor(.white, size: CGSize(width: 5, height: 5)).cgImage
        return confetti
    }
}

extension UIImage {
    static func imageWithColor(_ color: UIColor, size: CGSize) -> UIImage {
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        color.setFill()
        UIRectFill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }
}
iOS Swift UIVieView CaemitterLayer

评论

0赞 DonMag 9/8/2023
这篇文章会快速搜索一下: medium.com/@dkw5877/fun-with-particle-emitters-dcc438c4639f -- 它有一个“火箭像烟花一样发射和爆炸”——这可能是一些很好的示例代码供你深入研究。我还建议先用一个视图来处理效果。

答: 暂无答案