在视图的每一侧对齐四个caemitterlayer(),向内指向

发布于 2025-01-23 21:56:52 字数 3098 浏览 2 评论 0原文

我正在为子视图添加4 caemitterlayers。每个caemitterlayer都是一行,将位于每一侧。旋转将通过CGAFFINETRANSFORM 控制

问题:

我无法获得.left和.rigrt。

我的 >这是我的进步:

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
}

正在发生的事情:

https://i.sstatic.net/0r8qu.gif“ alt =“粒子系统的gif动画”>

我的问题

我如何获得.left> .left.right caemitterlayer与灰色视图的左侧和右侧正确对齐?

绿色三角形图像:

“绿色三角形图像”

I'm working on adding 4 CAEmitterLayers to a subview. Each CAEmitterLayer is a line, and will be positioned on each side. Rotation will be controlled via CGAffineTransform

My problem:

I can't get the .Left and .Right emitterPosition to properly line up with the left and right side of the view

Here's my progress:

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
}

What's happening:

gif animation of particle system

My question

How can I get the .Left and .Right CAEmitterLayer to properly align with the left side and right side of the gray view?

Green Triangle Image:

Green Triangle Image

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

紫南 2025-01-30 21:56:52

您尝试使用CGAFFINETRANSFORM的方法是有希望的,因为线发射器是仅具有宽度维度的水平线。通过旋转它,您可以将其从左侧或右侧发射。

但是,您需要将视图高度作为宽度和视图宽度作为高度使用发射极界限。

particleEmitter.bounds = CGRect(x: 0, y: 0, width: bounds.size.height, height: bounds.size.width)

因此,将发射的宽度设置为视图高度:

particleEmitter.emitterSize = CGSize(width: bounds.size.height, height: 0)

必须以相同的方式调整发射极位置。

为什么这样?查看以下图表,顶部发射:

​而且,排放量也不可见,因为它们会在左边很大。

将发射器在左侧或右侧的距>。

当然,从顶部和底部发出的发射器应获得正常的界限,只需要像您的问题中那样旋转。

提示

在您的createparticles方法您调用self.layoutsubviews()。应该避免。

Apple Docs明确说明:

您不应该直接调用此方法。

请参阅 httpps:// https://developer.apple.apple.com/documenter.com/documentation/uikitation/uikit/uikit/uikit/uiview/1666222224242 -layoutsubviews

取而代之的是,您可以覆盖layoutsubviews,然后从那里调用createparticles方法。确保通过删除任何先前创建的发射极层。

一件小事:Swift Switch Case从约定的小写字母开始。

代码

一个完整的示例可以帮助您入门,然后看起来像这样:

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 { $0.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
    }
}

test

“

Your approach to try to use CGAffineTransform is promising because a line emitter is a horizontal line that has only a width dimension. By rotating it, you can have it emit from the left or right.

However you need to use emitter bounds with the view height as width and the view width as height.

particleEmitter.bounds = CGRect(x: 0, y: 0, width: bounds.size.height, height: bounds.size.width)

Accordingly, one sets the width of the emitterSize to the height of the view:

particleEmitter.emitterSize = CGSize(width: bounds.size.height, height: 0)

The emitter position must be adjusted in the same way.

Why is this so? Take a look at the following illustration with an emission from the top:

rotation illustration

If you rotate the layer by 90 degrees you would only cover a small area in the middle. Also the emissions would not be visible, because they would be to much outside to the left.

The difference between having the emitter on the left or the right is just a call to setAffineTransform with either -.pi / 2 or .pi / 2.

The emitters from top and bottom of course should get the normal bounds, they only need to be rotated as you do in your question.

Hints

In your createParticles method you call self.layoutSubviews(). That should be avoided.

Apple docs explicitly state:

You should not call this method directly.

see https://developer.apple.com/documentation/uikit/uiview/1622482-layoutsubviews.

Instead you could override layoutSubviews and call your createParticles methods from there. Make sure to remove any previously created emitter layers by removing them.

One small thing: Swift switch cases start with a lowercase letter by convention.

Code

A complete example to help you get started might then look something like this:

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 { $0.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
    }
}

Test

demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文