CAEmitterLayer перестает отображаться

Я адаптировал этот код для SwiftUI для отображения частиц конфетти, но иногда эмиттер частиц не работает. Я заметил, что это часто происходит после отправки в фоновый режим (не полного уничтожения приложения) и его повторного открытия или просто после того, как приложение поработает некоторое время, а затем повторит попытку.

Я пытался использовать beginTime как другие ответы (как на эмиттере, так и на ячейках), но это полностью ломает ситуацию. Я также пробовал переключать различные другие свойства эмиттера (birthRate, isHidden). Возможно, это связано с тем, что я адаптирую это с помощью UIViewRepresentable. Кажется, что слой эмиттера просто исчезает, хотя консоль отладки говорит, что он все еще виден.

class ConfettiParticleView: UIView {
    var emitter: CAEmitterLayer!
    public var colors: [UIColor]!
    public var intensity: Float!
    private var active: Bool!

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    func setup() {
        colors = [UIColor(Color.red),
                  UIColor(Color.blue),
                  UIColor(Color.orange),
                ]
        intensity = 0.7
        active = false
        emitter = CAEmitterLayer()

        emitter.emitterPosition = CGPoint(x: UIScreen.main.bounds.width / 2.0, y: 0) // emit from top of view
        emitter.emitterShape = .line
        emitter.emitterSize = CGSize(width: UIScreen.main.bounds.width, height: 100) // line spans the whole top of view
//        emitter.beginTime = CACurrentMediaTime()
        var cells = [CAEmitterCell]()
        for color in colors {
            cells.append(confettiWithColor(color: color))
        }

        emitter.emitterCells = cells
        emitter.allowsGroupOpacity = false
        self.layer.addSublayer(emitter)
    }

    func startConfetti() {
        emitter.lifetime = 1
        // i've tried toggling other properties here like birthRate, speed
        active = true
    }

    func stopConfetti() {
        emitter.lifetime = 0
        active = false
    }

    func confettiWithColor(color: UIColor) -> CAEmitterCell {
        let confetti = CAEmitterCell()
        confetti.birthRate = 32.0 * intensity
        confetti.lifetime = 15.0 * intensity
        confetti.lifetimeRange = 0
        confetti.name = "confetti"
        confetti.color = color.cgColor
        confetti.velocity = CGFloat(450.0 * intensity) // orig 450
        confetti.velocityRange = CGFloat(80.0 * intensity)
        confetti.emissionLongitude = .pi
        confetti.emissionRange = .pi / 4
        confetti.spin = CGFloat(3.5 * intensity)
        confetti.spinRange = 300 * (.pi / 180.0)
        confetti.scaleRange = CGFloat(intensity)
        confetti.scaleSpeed = CGFloat(-0.1 * intensity)
        confetti.contents = #imageLiteral(resourceName: "confetti").cgImage
        confetti.beginTime = CACurrentMediaTime()
        return confetti
    }

    func isActive() -> Bool {
        return self.active
    }
}

представляемый вид

struct ConfettiView: UIViewRepresentable {
    @Binding var isStarted: Bool
    
    func makeUIView(context: Context) -> ConfettiParticleView {
        return ConfettiParticleView()
    }
    
    func updateUIView(_ uiView: ConfettiParticleView, context: Context) {
        if isStarted && !uiView.isActive() {
            uiView.startConfetti()
            print("confetti started")
        } else if !isStarted {
            uiView.stopConfetti()
            print("confetti stopped")
        }
    }
}

представление SwiftUI для тестирования

struct ConfettiViewTest: View {
    @State var isStarted = false
    
    var body: some View {
        ZStack {
            ConfettiView(isStarted: $isStarted)
                .ignoresSafeArea()
            
            Button(action: {
                isStarted = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    isStarted = false
                }
            }) {
                Text("toggle")
                    .padding()
                    .background(Color.white)
            }
        }
    }
}

person bze12    schedule 14.04.2021    source источник
comment
Вы видите, что конфетти консоли запускались и останавливались в то время, когда вы ожидаете, даже когда само конфетти не появляется?   -  person matt    schedule 14.04.2021
comment
Отвечает ли это на ваш вопрос stackoverflow.com/a/61711171/12299030?   -  person Asperi    schedule 14.04.2021
comment
@matt да, я вижу, как они появляются в консоли   -  person bze12    schedule 15.04.2021
comment
@Asperi, есть ли в этом ответе что-то конкретное, что может мне помочь? Я вижу, что он настраивает эмиттер с uiviewrepresentable, как я это сделал, но моя проблема заключается в включении и выключении эмиттера.   -  person bze12    schedule 16.04.2021