Reputation: 3961
I'm working on creating a CAEmitterLayer that's the height of the screen, and pushed off -X, so the CAEmitterCells travel from left (off the screen) to upper right.
There's an issue I am running into where the emitterSize height property of CAEmitterLayer is being ignored. This is causing all the cells to emit from a single point, and not what's set with emitterSize.
Here's the emitter:
emitter.emitterPosition = CGPoint(x: -50, y: (view.frame.height / 2))
emitter.emitterShape = kCAEmitterLayerLine
emitter.emitterSize = CGSize(width: 2, height: view.frame.height)
i mentioned emitterSize height is not working, because if i change the width of the above emitterSize, I can see the width changing properly! No matter what value I put for height... it gets ignored.
And the CAEmitterCells
cell.birthRate = 10
cell.lifetime = 10
cell.velocity = CGFloat(50)
cell.emissionLongitude = (45 * (.pi/180))
How can I set the emitterSize width to be 2 points wide and the height of the view?
Upvotes: 2
Views: 1028
Reputation: 385500
kCAEmitterLayerLine
is always a horizontal line of zero thickness. Only emitterSize.width
is used.
You can use the line shape vertically by setting your emitter layer's transform to a rotation. Playground example:
import UIKit
import PlaygroundSupport
class VerticalEmitterView: UIView {
let emitter = CAEmitterLayer()
override func layoutSubviews() {
super.layoutSubviews()
let bounds = self.bounds
emitter.position = CGPoint(x: bounds.midX, y: bounds.midY)
emitter.bounds = CGRect(x: 0, y: 0, width: bounds.size.height, height: bounds.size.width)
emitter.emitterPosition = CGPoint(x: bounds.width / 2, y: -50)
emitter.emitterSize = CGSize(width: emitter.bounds.size.width, height: 0)
if emitter.superlayer != self.layer {
emitter.setAffineTransform(CGAffineTransform(rotationAngle: -.pi / 2))
emitter.emitterShape = kCAEmitterLayerLine
let cell = CAEmitterCell()
cell.birthRate = 100
cell.lifetime = 10
cell.velocity = 50
cell.emissionLongitude = .pi
cell.color = UIColor.red.cgColor
let particleSize = CGSize(width: 5, height: 5)
let image = UIGraphicsImageRenderer(size: particleSize).image(actions: { (rc) in
UIColor.white.setFill()
let gc = UIGraphicsGetCurrentContext()
UIBezierPath(ovalIn: CGRect(origin: .zero, size: particleSize)).fill()
})
cell.contents = image.cgImage
emitter.emitterCells = [cell]
layer.addSublayer(emitter)
}
}
}
let rootView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
rootView.backgroundColor = .white
let emitterView = VerticalEmitterView(frame: rootView.bounds)
rootView.addSubview(emitterView)
PlaygroundPage.current.liveView = rootView
Result:
(The discontinuity is because this GIF is a one-second loop.)
Upvotes: 3
Reputation: 1
I had exactly the same problem. Looking through Apple's documentation, it looks like if the emitter shape is kCAEmitterLayerLine, it ignores the height of the emitter.
The not-ideal workaround I found was to use a kcaEmitterLayerRectangle with a large enough height so that one side of the rectangle is where you wanted the line to be.
Upvotes: 0