|
6 | 6 |
|
7 | 7 | SwiftUI animation is compelling and superb. You can add incredible effects and beautiful animations to your apps with minimal effort. **Why use an animation library instead of creating these tiny effects yourself?** Get inspiration from [here](OpenSwiftUIAnimations) and start building your SwiftUI animations today. Most animations here are based on the animations section in the [Apple Developer Documentation](https://developer.apple.com/documentation/swiftui/animations). Check out the [Xcode project](OpenSwiftUIAnimations) for examples of the new [Phase Animator](https://developer.apple.com/documentation/swiftui/phaseanimator), Symbol Effects, [Keyframe Animator](https://developer.apple.com/documentation/swiftui/keyframeanimator), and [Spring Animations](https://developer.apple.com/documentation/swiftui/spring) for iOS 17 and beyond. Do you want to see an animation that is not here, or did you find an engaging one to add? Contact me on X: [@amos_gyamfi](https://twitter.com/amos_gyamfi) or add it as a task in the [project's backlog](https://github.com/users/amosgyamfi/projects/1/views/1). |
8 | 8 |
|
| 9 | +### SwiftUI Fireworks Animation: Before running the code, ensure you have a small image like "Spark.png" in your assets catalog. |
| 10 | + |
| 11 | + |
| 12 | +```swift |
| 13 | +import SwiftUI |
| 14 | +import UIKit // Still needed for CAEmitterLayer, UIView, UIColor, UIImage |
| 15 | + |
| 16 | +// MARK: - UIViewRepresentable Wrapper |
| 17 | +struct ParticleEmitterView: UIViewRepresentable { |
| 18 | + |
| 19 | + // This matches the original fixed size, but SwiftUI might resize it. |
| 20 | + // We'll use relative positioning instead of hardcoding based on this size. |
| 21 | + // let originalSize = CGSize(width: 625.0, height: 1118.0) |
| 22 | + |
| 23 | + // You can add @Binding properties here if you want to control |
| 24 | + // emitter parameters dynamically from SwiftUI state. |
| 25 | + |
| 26 | + func makeUIView(context: Context) -> UIView { |
| 27 | + let size = CGSize(width: 625.0, height: 1118.0) |
| 28 | + let host = UIView(frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)) |
| 29 | + |
| 30 | + let particlesLayer = CAEmitterLayer() |
| 31 | + particlesLayer.frame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height) |
| 32 | + |
| 33 | + host.layer.addSublayer(particlesLayer) |
| 34 | + host.layer.masksToBounds = true |
| 35 | + |
| 36 | + particlesLayer.backgroundColor = UIColor.black.cgColor |
| 37 | + particlesLayer.emitterShape = .point |
| 38 | + particlesLayer.emitterPosition = CGPoint(x: 312.5, y: 1018.0) |
| 39 | + particlesLayer.emitterSize = CGSize(width: 0.0, height: 0.0) |
| 40 | + particlesLayer.emitterMode = .outline |
| 41 | + particlesLayer.renderMode = .additive |
| 42 | + |
| 43 | + // Parent cell |
| 44 | + let cell1 = CAEmitterCell() |
| 45 | + cell1.name = "Parent" |
| 46 | + cell1.birthRate = 5.0 |
| 47 | + cell1.lifetime = 2.5 |
| 48 | + cell1.velocity = 300.0 |
| 49 | + cell1.velocityRange = 100.0 |
| 50 | + cell1.yAcceleration = -100.0 |
| 51 | + cell1.emissionLongitude = -90.0 * (.pi / 180.0) |
| 52 | + cell1.emissionRange = 45.0 * (.pi / 180.0) |
| 53 | + cell1.scale = 0.0 |
| 54 | + cell1.color = UIColor.white.cgColor |
| 55 | + cell1.redRange = 0.9 |
| 56 | + cell1.greenRange = 0.9 |
| 57 | + cell1.blueRange = 0.9 |
| 58 | + |
| 59 | + // Trail subcell |
| 60 | + let subcell1_1 = CAEmitterCell() |
| 61 | + subcell1_1.contents = UIImage(named: "Spark")?.cgImage |
| 62 | + subcell1_1.name = "Trail" |
| 63 | + subcell1_1.birthRate = 45.0 |
| 64 | + subcell1_1.lifetime = 0.5 |
| 65 | + subcell1_1.beginTime = 0.01 |
| 66 | + subcell1_1.duration = 1.7 |
| 67 | + subcell1_1.velocity = 80.0 |
| 68 | + subcell1_1.velocityRange = 100.0 |
| 69 | + subcell1_1.xAcceleration = 100.0 |
| 70 | + subcell1_1.yAcceleration = 350.0 |
| 71 | + subcell1_1.emissionLongitude = -360.0 * (.pi / 180.0) |
| 72 | + subcell1_1.emissionRange = 22.5 * (.pi / 180.0) |
| 73 | + subcell1_1.scale = 0.5 |
| 74 | + subcell1_1.scaleSpeed = 0.13 |
| 75 | + subcell1_1.alphaSpeed = -0.7 |
| 76 | + subcell1_1.color = UIColor.white.cgColor |
| 77 | + |
| 78 | + // Firework subcell |
| 79 | + let subcell1_2 = CAEmitterCell() |
| 80 | + subcell1_2.contents = UIImage(named: "Spark")?.cgImage |
| 81 | + subcell1_2.name = "Firework" |
| 82 | + subcell1_2.birthRate = 20000.0 |
| 83 | + subcell1_2.lifetime = 15.0 |
| 84 | + subcell1_2.beginTime = 1.6 |
| 85 | + subcell1_2.duration = 0.1 |
| 86 | + subcell1_2.velocity = 190.0 |
| 87 | + subcell1_2.yAcceleration = 80.0 |
| 88 | + subcell1_2.emissionRange = 360.0 * (.pi / 180.0) |
| 89 | + subcell1_2.spin = 114.6 * (.pi / 180.0) |
| 90 | + subcell1_2.scale = 0.1 |
| 91 | + subcell1_2.scaleSpeed = 0.09 |
| 92 | + subcell1_2.alphaSpeed = -0.7 |
| 93 | + subcell1_2.color = UIColor.white.cgColor |
| 94 | + |
| 95 | + // Set up emitter cells hierarchy |
| 96 | + cell1.emitterCells = [subcell1_1, subcell1_2] |
| 97 | + particlesLayer.emitterCells = [cell1] |
| 98 | + |
| 99 | + return host |
| 100 | + } |
| 101 | + |
| 102 | + func updateUIView(_ uiView: UIView, context: Context) {} |
| 103 | +} |
| 104 | + |
| 105 | +struct Gemini25FireworksView: View { |
| 106 | + var body: some View { |
| 107 | + ZStack { |
| 108 | + Color.black.edgesIgnoringSafeArea(.all) |
| 109 | + ParticleEmitterView() |
| 110 | + } |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +#Preview { |
| 115 | + Gemini25FireworksView() |
| 116 | +} |
| 117 | +``` |
| 118 | +--- |
| 119 | + |
9 | 120 | ### Thinking, Weighing Options, Evaluating Sentence |
10 | 121 |  |
11 | 122 | --- |
|
0 commit comments