【问题标题】:How to use CAEmitterLayer on macOS in a SwiftUI app using NSViewRepresentable如何在 macOS 上使用 NSViewRepresentable 在 SwiftUI 应用程序中使用 CAEmitterLayer
【发布时间】:2021-10-20 13:17:01
【问题描述】:

我想在基于 SwiftUI 的 macOS 应用中使用 CAEmitterLayer

问题:图层本身完全可见,但不发射任何粒子。

→ Here’s my demo project on GitHub

我基本上为处理发射器层本身的自定义类EmitterNSView: NSView 构建了一个NSViewRepresentable

final class EmitterNSView: NSView {

    private let emitterLayer: CAEmitterLayer = {
        let layer = CAEmitterLayer()
        layer.backgroundColor = NSColor.green.withAlphaComponent(0.33).cgColor
        return layer
    }()

    private let emitterCells: [CAEmitterCell] = {
        // https://developer.apple.com/documentation/quartzcore/caemitterlayer
        let cell = CAEmitterCell()
        cell.name = "someParticle"
        cell.birthRate = 10
        cell.lifetime = 5.0
        cell.velocity = 100
        cell.velocityRange = 50
        cell.emissionLongitude = 0.0
        cell.emissionRange = CGFloat.pi * 2.0
        cell.spinRange = 5
        cell.scale = 1.0
        cell.scaleRange = 0.25
        cell.alphaSpeed = 0.25
        cell.contents = NSImage(named: "whiteParticle.png")!.cgImage
        cell.color = NSColor.systemPink.cgColor
        cell.xAcceleration = 4
        cell.yAcceleration = 3
        cell.zAcceleration = 2
        return [cell]
    }()

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        self.wantsLayer = true
        self.layer = CALayer()
        self.layer?.autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
        self.configureEmitterLayer()
        self.layer?.addSublayer(self.emitterLayer)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layout() {
        super.layout()
        self.configureEmitterLayer()
    }

    override func updateLayer() {
        super.updateLayer()
        self.configureEmitterLayer()
    }

    func configureEmitterLayer() {
        self.emitterLayer.frame = self.frame
        self.emitterLayer.autoresizingMask = [.layerHeightSizable, .layerWidthSizable]
        self.emitterLayer.masksToBounds = false
        self.emitterLayer.drawsAsynchronously = true
        self.emitterLayer.emitterMode = .points
        self.emitterLayer.birthRate = 2
        self.emitterLayer.emitterShape = CAEmitterLayerEmitterShape.line
        self.emitterLayer.emitterSize = CGSize(width: frame.width * 0.5, height: frame.height * 0.5)
        self.emitterLayer.emitterPosition = CGPoint.zero
        self.emitterLayer.renderMode = CAEmitterLayerRenderMode.additive
        self.emitterLayer.emitterCells = self.emitterCells
        self.emitterLayer.zPosition = 10
        self.emitterLayer.beginTime = CACurrentMediaTime()
        self.emitterLayer.speed = 1.5
        self.emitterLayer.emitterCells = self.emitterCells
    
    }

}

我可以清楚地看到应用程序中图层的绿色背景这一事实表明单元格有问题?在这一点上感到迷茫。

UIKit 中非常相似的实现工作得很好。

如何在 macOS 上基于 SwiftUI 的应用程序中使用 CAEmitterLayer

【问题讨论】:

    标签: swift swiftui caemitterlayer caemittercell nsviewrepresentable


    【解决方案1】:

    在将 NSImage 转换为 CGImage 时使用 cgImage(forProposedRect:context:hints:)

    cell.contents = NSImage(named:"whiteParticle.png").flatMap {
        return $0.cgImage(forProposedRect: nil, context: nil, hints: nil)
    }
    

    【讨论】:

    • 这种方法效果很好。非常感谢@RTXGamer,我自己永远不会想到它。那么这是否意味着NSImage 上的cgImage 属性已损坏?很想了解这里的问题!
    • @ixany cgImage 没有属性,请检查定义。您正在调用 func cgImage(forProposedRect proposedDestRect: UnsafeMutablePointer<NSRect>?, context referenceContext: NSGraphicsContext?, hints: [NSImageRep.HintKey : Any]?) -> CGImage? 方法,其中所有参数都是可选的。
    猜你喜欢
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-27
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多