在视图的每一侧对齐四个 CAEmitterLayer(),指向内部
Aligning four CAEmitterLayer() on each side of view, pointing inward
我正在努力将 4 CAEmitterLayers
添加到子视图。每个 CAEmitterLayer
是一条线,将被定位在每一边。旋转将通过 CGAffineTransform
控制
我的问题:
我无法让 .Left 和 .Right emitterPosition 与视图的左侧和右侧正确对齐
这是我的进度:
override func awakeFromNib() {
super.awakeFromNib()
self.layer.cornerRadius = GlobalConstants.smallCornerRadius
createParticles(direction: .Up)
createParticles(direction: .Down)
createParticles(direction: .Left)
createParticles(direction: .Right)
}
enum EmitTo {
case Up
case Down
case Left
case Right
}
func createParticles(direction: EmitTo) {
self.layoutSubviews()
let particleEmitter = CAEmitterLayer()
particleEmitter.position = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
particleEmitter.bounds = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)
if direction == .Up {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: 0))
} else if (direction == .Down) {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: .pi))
} else if (direction == .Left) {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: .pi / 2))
} else if (direction == .Right) {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: -.pi / 2))
}
if direction == .Up || direction == .Down {
particleEmitter.emitterPosition = CGPoint(x: self.frame.width / 2, y: 0)
}
if direction == .Left {
particleEmitter.emitterPosition = CGPoint(x: self.frame.height / 2, y: self.frame.height)
}
if direction == .Right {
particleEmitter.emitterPosition = CGPoint(x: self.frame.height / 2, y: -50)
}
particleEmitter.emitterSize = self.bounds.size
particleEmitter.emitterShape = CAEmitterLayerEmitterShape.line
particleEmitter.zPosition = 1
let triangle = makeEmitterCell(direction: direction)
particleEmitter.emitterCells = [triangle]
self.layer.addSublayer(particleEmitter)
}
func makeEmitterCell(direction: EmitTo) -> CAEmitterCell {
let cell = CAEmitterCell()
cell.birthRate = 25
cell.lifetime = 3
cell.lifetimeRange = 0
cell.velocity = 10
cell.velocityRange = 5
cell.emissionLongitude = .pi
cell.spin = 2
cell.spinRange = 3
cell.scale = 0.4
cell.scaleRange = 0.6
cell.scaleSpeed = -0.10
cell.contents = UIImage(named: "greenTriangle")?.cgImage
return cell
}
发生了什么:
我的问题
如何让 .Left
和 .Right
CAEmitterLayer
与灰色视图的左侧和右侧正确对齐?
绿色三角形图像:
您尝试使用 CGAffineTransform
的方法很有前途,因为线发射器是一条只有宽度尺寸的水平线。通过旋转它,你可以让它从左边或右边发射。
但是您需要使用发射器边界,视图高度作为宽度,视图宽度作为高度。
particleEmitter.bounds = CGRect(x: 0, y: 0, width: bounds.size.height, height: bounds.size.width)
相应地,将 emitterSize 的宽度设置为视图的高度:
particleEmitter.emitterSize = CGSize(width: bounds.size.height, height: 0)
必须以同样的方式调整发射器位置。
为什么会这样?看看下面的插图,上面有一个发射:
如果将图层旋转 90 度,您只会覆盖中间的一小块区域。排放物也将不可见,因为它们在左侧太远了。
发射器在左边或右边的区别只是用 -.pi / 2
或 .pi / 2
调用 setAffineTransform
。
顶部和底部的发射器当然应该有正常的边界,它们只需要像你在问题中那样旋转。
提示
在您的 createParticles
方法中调用 self.layoutSubviews()
。应该避免这种情况。
Apple 文档明确指出:
You should not call this method directly.
参见 https://developer.apple.com/documentation/uikit/uiview/1622482-layoutsubviews。
相反,您可以覆盖 layoutSubviews
并从那里调用您的 createParticles
方法。确保移除之前创建的发射器层。
一件小事:Swift switch cases 按照惯例以小写字母开头。
代码
帮助您入门的完整示例可能如下所示:
import UIKit
class EmitterView: UIView {
private var emitters = [CAEmitterLayer]()
enum EmitTo {
case up
case down
case left
case right
}
override func layoutSubviews() {
super.layoutSubviews()
emitters.forEach { [=12=].removeFromSuperlayer() }
emitters.removeAll()
createParticles(direction: .up)
createParticles(direction: .down)
createParticles(direction: .left)
createParticles(direction: .right)
}
func createParticles(direction: EmitTo) {
let particleEmitter = CAEmitterLayer()
emitters.append(particleEmitter)
particleEmitter.position = CGPoint(x: bounds.midX, y: bounds.midY)
particleEmitter.emitterShape = .line
switch direction {
case .up, .down:
particleEmitter.bounds = self.bounds
particleEmitter.emitterPosition = CGPoint(x: bounds.size.width / 2, y: 0)
particleEmitter.emitterSize = CGSize(width: bounds.size.width, height: 0)
if direction == .up {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: -.pi))
}
case .left, .right:
particleEmitter.bounds = CGRect(x: 0, y: 0, width: bounds.size.height, height: bounds.size.width)
particleEmitter.emitterPosition = CGPoint(x: bounds.height / 2, y: 0)
particleEmitter.emitterSize = CGSize(width: bounds.size.height, height: 0)
let rotationAngle: CGFloat = direction == EmitTo.left ? -.pi / 2 : .pi / 2
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: rotationAngle))
}
particleEmitter.emitterCells = [makeEmitterCell()]
layer.addSublayer( particleEmitter)
}
func makeEmitterCell() -> CAEmitterCell {
let cell = CAEmitterCell()
cell.birthRate = 25
cell.lifetime = 3
cell.lifetimeRange = 0
cell.velocity = 10
cell.velocityRange = 5
cell.emissionLongitude = .pi
cell.spin = 2
cell.spinRange = 3
cell.scale = 0.4
cell.scaleRange = 0.6
cell.scaleSpeed = -0.10
cell.contents = UIImage(named: "greenTriangle")?.cgImage
return cell
}
}
测试
我正在努力将 4 CAEmitterLayers
添加到子视图。每个 CAEmitterLayer
是一条线,将被定位在每一边。旋转将通过 CGAffineTransform
我的问题:
我无法让 .Left 和 .Right emitterPosition 与视图的左侧和右侧正确对齐
这是我的进度:
override func awakeFromNib() {
super.awakeFromNib()
self.layer.cornerRadius = GlobalConstants.smallCornerRadius
createParticles(direction: .Up)
createParticles(direction: .Down)
createParticles(direction: .Left)
createParticles(direction: .Right)
}
enum EmitTo {
case Up
case Down
case Left
case Right
}
func createParticles(direction: EmitTo) {
self.layoutSubviews()
let particleEmitter = CAEmitterLayer()
particleEmitter.position = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
particleEmitter.bounds = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)
if direction == .Up {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: 0))
} else if (direction == .Down) {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: .pi))
} else if (direction == .Left) {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: .pi / 2))
} else if (direction == .Right) {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: -.pi / 2))
}
if direction == .Up || direction == .Down {
particleEmitter.emitterPosition = CGPoint(x: self.frame.width / 2, y: 0)
}
if direction == .Left {
particleEmitter.emitterPosition = CGPoint(x: self.frame.height / 2, y: self.frame.height)
}
if direction == .Right {
particleEmitter.emitterPosition = CGPoint(x: self.frame.height / 2, y: -50)
}
particleEmitter.emitterSize = self.bounds.size
particleEmitter.emitterShape = CAEmitterLayerEmitterShape.line
particleEmitter.zPosition = 1
let triangle = makeEmitterCell(direction: direction)
particleEmitter.emitterCells = [triangle]
self.layer.addSublayer(particleEmitter)
}
func makeEmitterCell(direction: EmitTo) -> CAEmitterCell {
let cell = CAEmitterCell()
cell.birthRate = 25
cell.lifetime = 3
cell.lifetimeRange = 0
cell.velocity = 10
cell.velocityRange = 5
cell.emissionLongitude = .pi
cell.spin = 2
cell.spinRange = 3
cell.scale = 0.4
cell.scaleRange = 0.6
cell.scaleSpeed = -0.10
cell.contents = UIImage(named: "greenTriangle")?.cgImage
return cell
}
发生了什么:
我的问题
如何让 .Left
和 .Right
CAEmitterLayer
与灰色视图的左侧和右侧正确对齐?
绿色三角形图像:
您尝试使用 CGAffineTransform
的方法很有前途,因为线发射器是一条只有宽度尺寸的水平线。通过旋转它,你可以让它从左边或右边发射。
但是您需要使用发射器边界,视图高度作为宽度,视图宽度作为高度。
particleEmitter.bounds = CGRect(x: 0, y: 0, width: bounds.size.height, height: bounds.size.width)
相应地,将 emitterSize 的宽度设置为视图的高度:
particleEmitter.emitterSize = CGSize(width: bounds.size.height, height: 0)
必须以同样的方式调整发射器位置。
为什么会这样?看看下面的插图,上面有一个发射:
如果将图层旋转 90 度,您只会覆盖中间的一小块区域。排放物也将不可见,因为它们在左侧太远了。
发射器在左边或右边的区别只是用 -.pi / 2
或 .pi / 2
调用 setAffineTransform
。
顶部和底部的发射器当然应该有正常的边界,它们只需要像你在问题中那样旋转。
提示
在您的 createParticles
方法中调用 self.layoutSubviews()
。应该避免这种情况。
Apple 文档明确指出:
You should not call this method directly.
参见 https://developer.apple.com/documentation/uikit/uiview/1622482-layoutsubviews。
相反,您可以覆盖 layoutSubviews
并从那里调用您的 createParticles
方法。确保移除之前创建的发射器层。
一件小事:Swift switch cases 按照惯例以小写字母开头。
代码
帮助您入门的完整示例可能如下所示:
import UIKit
class EmitterView: UIView {
private var emitters = [CAEmitterLayer]()
enum EmitTo {
case up
case down
case left
case right
}
override func layoutSubviews() {
super.layoutSubviews()
emitters.forEach { [=12=].removeFromSuperlayer() }
emitters.removeAll()
createParticles(direction: .up)
createParticles(direction: .down)
createParticles(direction: .left)
createParticles(direction: .right)
}
func createParticles(direction: EmitTo) {
let particleEmitter = CAEmitterLayer()
emitters.append(particleEmitter)
particleEmitter.position = CGPoint(x: bounds.midX, y: bounds.midY)
particleEmitter.emitterShape = .line
switch direction {
case .up, .down:
particleEmitter.bounds = self.bounds
particleEmitter.emitterPosition = CGPoint(x: bounds.size.width / 2, y: 0)
particleEmitter.emitterSize = CGSize(width: bounds.size.width, height: 0)
if direction == .up {
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: -.pi))
}
case .left, .right:
particleEmitter.bounds = CGRect(x: 0, y: 0, width: bounds.size.height, height: bounds.size.width)
particleEmitter.emitterPosition = CGPoint(x: bounds.height / 2, y: 0)
particleEmitter.emitterSize = CGSize(width: bounds.size.height, height: 0)
let rotationAngle: CGFloat = direction == EmitTo.left ? -.pi / 2 : .pi / 2
particleEmitter.setAffineTransform(CGAffineTransform(rotationAngle: rotationAngle))
}
particleEmitter.emitterCells = [makeEmitterCell()]
layer.addSublayer( particleEmitter)
}
func makeEmitterCell() -> CAEmitterCell {
let cell = CAEmitterCell()
cell.birthRate = 25
cell.lifetime = 3
cell.lifetimeRange = 0
cell.velocity = 10
cell.velocityRange = 5
cell.emissionLongitude = .pi
cell.spin = 2
cell.spinRange = 3
cell.scale = 0.4
cell.scaleRange = 0.6
cell.scaleSpeed = -0.10
cell.contents = UIImage(named: "greenTriangle")?.cgImage
return cell
}
}
测试