Using SwiftUI Effects Library: How to Add Particle Effects to iOS Apps

10 min read

In this article, you will discover how to integrate and render particles such as snow, confetti, rain, smoke, and fireworks to iOS applications effortlessly and without knowing the Physics behind these animations.

Amos G.
Amos G.
Published November 15, 2022
Effects Library Header Image

Creating particle animations similar to the iMessage screen and bubble effects in iOS can be difficult. The main reason is that the Core Animation Emitter Layer that allows you to animate, emit and render particle effects is complex to set up and configure due to its large number of parameters.

In this article, you will discover how to integrate and render particles such as snow, confetti, rain, smoke, and fireworks to iOS applications effortlessly and without knowing the Physics behind these animations.

What is Effects Library?

The SwiftUI Effects Library allows Swift and iOS developers to build sophisticated and realistic particle systems with minimal effort and without understanding the underlying complicated emission engine behind Core Animation.

Using Stream Chat SwiftUI

In this tutorial, you will use a blank SwiftUI project and Stream Chat SwiftUI SDK to demonstrate how the Effects Library works on standard SwiftUI components. You can download the complete project on GitHub and explore how the effects work with a chat sample application from Stream. Check out the links below if you are new to Stream Chat SwiftUI.

Note: You are not obliged to use Stream Chat SwiftUI to complete this tutorial. You can use any SwiftUI project to follow along. The Effects Library works with any SwiftUI project.

Create a Blank SwiftUI Project

This project uses Xcode 14, but you can use version 13 or later. Launch Xcode and create a new SwiftUI project.

  1. Select iOS as the platform.
  2. Choose App under the Application section and click Next.
Create Xcode project
  1. Enter EffectsLibraryStreamChatSwiftUI as the product name, or use any name you prefer and click Next to choose a location to save the project.
Xcode project name

Fetch the Effects Library as a Package Dependency

The simplest way to integrate the Effects Library package with SwiftUI projects is by using Swift Package Manager. To add it to your project, you should use the GitHub repository https://github.com/GetStream/effects-library.

  1. On the Xcode toolbar, click File -> Add Packages…, and paste the URL above in the search bar on the top-right window as illustrated in the image below.
Fetch the effects library
  1. Leave the Dependency Rule as Up to Next Major Version and click the Add Package button.
  2. Wait for the screen that appears to select the SwiftUI project name as the target.
  3. Click the Add Package button again to integrate the effects package successfully.

Fetch the Stream Chat SwiftUI SDK as a Package Dependency

Note: You can skip this section if you want to integrate the Effects Library with a different SwiftUI app.

To add the Stream SDK to your SwiftUI app, you can fetch it from GitHub. You should add the SDK as a package dependency using Swift Package Manager in the same way as how to add the Effects Library to the Xcode project.

Stream chat SwiftUI SDK

After installing the Effects Library and the Stream SwiftUI SDK, you will find them in the bottom left of the project navigator under Package Dependencies.

Package dependencies

Setup the SDK

This tutorial does not cover setting up the SwiftUI messaging SDK with the Xcode project. To learn more about configuring it to work with a SwiftUI app, check out this video that shows you How To Add Real-Time Chat Messaging to Your SwiftUI App.

How To Add Default Effects to SwiftUI Views

The Effects Library has six built-in animations and effects that you can add directly to your layout and composition in SwiftUI. There are snow, rain, fire, fireworks, smoke, and confetti animations ready to add to any SwiftUI content. You can include them in your SwiftUI app or project by following the steps below.

  1. Add a new Swift file ContentView.swift to the SwiftUI app folder in the project navigator.
  2. To make the effects available in ContentView.swift, you should import the library to the top of the file import EffectsLibrary.
  3. Add any of the six effects to the body of the ContentView struct. You can do this by calling their names as specified below.
SnowView()
RainView()
FireView()
FireworksView()
SmokeView()
ConfettiView()

You can use the code below to test and explore the effects using the Xcode's simulator or previews. Note: These are the default animations from the effects library.

//  ContentView.swift
//  Effects Library Stream Chat SwiftUI

import SwiftUI
import EffectsLibrary

struct ContentView: View {
    var body: some View {
        //SnowView()
        //RainView()
        //FireView()
        //FireworksView()
        //SmokeView()
        ConfettiView()
    }
}

struct ContentView_Previews: PreviewProvider {
   static var previews: some View {
        ContentView()
            .preferredColorScheme(.dark)
    }
}

This video shows a preview of the confetti effect.

Modify the Default Animations To Create Your Own Effects

In this section, you will discover how to customize and tailor the default fireworks effect to your taste. The procedure you will use to modify the fireworks animation can apply to augment all the others.

Each of the effects accepts a configuration parameter. The configuration is specific to the type of effect but shares some options with others. It provides you the ability to customize the animations. The configuration parameter helps to access the Core Animation Emitter Layer properties like intensity, lifetime, initial velocity, emission range, and more.

How To Customize the Effect Configuration Parameters
To customize the particle animation parameters, open the ContentView.swift file you added in the previous section. Similarly, the fireworks method FireWorksView() accepts a parameter called config with the type FireworksConfig. To provide default parameters for the fireworks configuration:

  1. Initialize it as var config = FireworksConfig().
  2. Pass it as a parameter in the fireworks method FireworksView(config: config).

The video below shows the fireworks effect that has no customization.

Changing the Particle Intensity to High or Low
The first customization you may want the fireworks to have may be changing the rendering speed of the particle emissions and the rate at which the particles are born. Use the options such as low, medium, and high to implement the intensity enumeration public enum Intensity { case low, medium, high }. The default implementation is medium. Supposing you want to have a high-intensity. Add the high-intensity case to the fireworks configuration initialization as shown in the sample code below.

import SwiftUI
import EffectsLibrary

// HighIntensityFireworks.swift

struct HighIntensityFireworks: View {

    var config = FireworksConfig(
        intensity: .high
    )

    var body: some View {
        FireworksView(config: config)
    }
}

struct HighIntensityFireworks_Previews: PreviewProvider {
    static var previews: some View {
        HighIntensityFireworks()
            .preferredColorScheme(.dark)
    }
}

The video below demonstrates the high-intensity fireworks emission. To get decreased intensity, change its value to low var config = FireworksConfig(intensity: .low).

Changing the Lifetime To Make the Emitter Cells Stay Shorter or Longer
The lifetime parameter of the particle system controls how long the emitter cells can stay before disappearing. This property is an enumeration of three cases, short, medium, and long public enum Lifetime { case short, medium, long }. To set this parameter in the configuration, you should use lifetime: .long or lifetime: .short.

How Initial Velocity Affects the Particle Emission
Another emission parameter you may want to change is the initial velocity. It defines the rate of change at the start of the animation. Specify the rate of change or the starting speed to transition the particles into seamless motion at the beginning. It has three enumeration cases, slow, medium, and fast. It has the default setting of medium. Try to set it to initialVelocity: .high and test how it works with the lifetime and intensity. The code snippet below uses the maximum settings for all three parameters described above.

import SwiftUI
import EffectsLibrary

struct HighIntensityFireworks: View {

    var config = FireworksConfig(
        intensity: .high,
        lifetime: .long,
        initialVelocity: .fast
    )

    var body: some View {
        FireworksView(config: config)
    }
}

struct HighIntensityFireworks_Previews: PreviewProvider {
    static var previews: some View {
        HighIntensityFireworks()
            .preferredColorScheme(.dark)
    }
}

The video below demonstrates the high intensity, long lifetime, and fast initial velocity animation.

Other Customizable Parameters
The other parameters you can change to create unique particle experiences are the backgroundColor, fadeOut, spreadRadius.
backgroundColor allows you to specify the color of the device screen.
fadeOut controls how fast or slow the emission particles disappear after creation.
spreadRadius defines the position within the particle system at which the cells spread out. To make the particles spread in all directions, you should set the value to spreadRadius: .high.

import SwiftUI
import EffectsLibrary

struct HighIntensityFireworks: View {

    var config = FireworksConfig(
        backgroundColor: .blue,
        intensity: .high,
        lifetime: .long,
        initialVelocity: .fast,
        fadeOut: .slow,
        spreadRadius: .high
    )

    var body: some View {
        FireworksView(config: config)
    }
}

struct HighIntensityFireworks_Previews: PreviewProvider {
    static var previews: some View {
        HighIntensityFireworks()
            .preferredColorScheme(.dark)
    }
}

The video below shows a custom background color, a slow fade out, and a high spread radius.

The particles will form a concave shape when you change the spread radius to spreadRadius: .low.

How To Change the Shape Content of the Particles
The particle content parameter is an array that allows you to replace the default content image used for rendering the particles. The possible options are images, emojis, and shapes. To modify the content of the fireworks effect, add the shape content array as the first parameter of the configuration variable. In the sample code below, the first element of the array is a blue triangle. The second element is a green square, and the last is a red circle. The last value of each element allows you to specify its size.

import SwiftUI
import EffectsLibrary

struct HighIntensityFireworks: View {

    var config = FireworksConfig(
        content: [
            .shape(.triangle, .blue, 2.0),
            .shape(.square, .green, 1.0),
            .shape(.circle, .red, 2.0)
        ],
        intensity: .high,
        lifetime: .long,
        initialVelocity: .fast,
        fadeOut: .slow,
        spreadRadius: .high
    )

    var body: some View {
        FireworksView(config: config)
    }
}

struct HighIntensityFireworks_Previews: PreviewProvider {
    static var previews: some View {
        HighIntensityFireworks()
            .preferredColorScheme(.dark)
    }
}

The video below shows the fireworks effect with customized shape content.

The .shape parameter uses multiple colors by default. So, specifying any of them with a solid color overrides the default color. To use the library-provided colors for elements of the array, you should set the color value as nil .shape(.circle, nil, 2.0).

import SwiftUI
import EffectsLibrary

struct HighIntensityFireworks: View {

    var config = FireworksConfig(
        content: [
            .shape(.triangle, .blue, 2.0),
            .shape(.square, .green, 1.0),
            .shape(.circle, nil, 2.0)
        ],
        intensity: .high,
        lifetime: .long,
        initialVelocity: .fast,
        fadeOut: .slow,
        spreadRadius: .high
    )

    var body: some View {
        FireworksView(config: config)
    }
}

struct HighIntensityFireworks_Previews: PreviewProvider {
    static var previews: some View {
        HighIntensityFireworks()
            .preferredColorScheme(.dark)
    }
}

The result of the code above is shown in the video below.

How To Change the Emoji Content of the Particles
The .emoji content parameter is similar to the .shape parameter. The only difference is that .emoji has no color element. The sample code below appends fire, fireworks, and wood emojis to the content. The value at the end of each emoji sets the size of the emoji.

import SwiftUI
import EffectsLibrary

struct HighIntensityFireworks: View {

    var config = FireworksConfig(
        content: [
            .shape(.triangle, .blue, 2.0),
            .shape(.square, .green, 1.0),
            .shape(.circle, nil, 2.0),
            .emoji("🔥", 5),
            .emoji("🎆", 5),
            .emoji("🪵", 10)
        ],
        intensity: .high,
        lifetime: .long,
        initialVelocity: .fast,
        fadeOut: .slow,
        spreadRadius: .high
    )

    var body: some View {
        FireworksView(config: config)
    }
}

struct HighIntensityFireworks_Previews: PreviewProvider {
    static var previews: some View {
        HighIntensityFireworks()
            .preferredColorScheme(.dark)
    }
}

The video below represents the combined emoji and shape fireworks effect.

How To Change the Content of the Particles With UIImage
The Effects Library supports changing the content of the particles using UIImage. It works in the same way as the shape and emoji parameters. For example, the code snippet .image(UIImage(named: "stream-logo")!, nil, 0.8) loads the image stream-logo from the assets library and use it as a source content of the fireworks.

Stream Chat: How To Add the Effects Library Animations to SwiftUI Components

In this section, you will customize the look and feel of the SwiftUI app you build by rendering animations from the Effects Library on chat bubbles and chat conversations background. This section does not cover setting up the Stream SDK to work with a SwiftUI project. Refer to the link above to learn about the procedure to set it up.

The previous chapters used the Xcode preview to display the animations. As a recommendation for this chapter, preview the animations using the Xcode simulator or an iOS device. The animations were previewed and tested using iPhone Pro Max.

Add the Snow Effect to Chat Bubbles
You can swap some SDK-provided components with custom SwiftUI views using views injection. There are several slottable views in the SDK. So, you can remove them in these slots and place other SwiftUI compositions.

In this section, you will add the snow effect as an overlay on the chat bubbles. Add a new Swift file CustomUIFactory.swift in the project navigator. You should implement some methods in this file to override the default SD components.

  1. Add the following imports.
import SwiftUI
import StreamChat
import StreamChatSwiftUI
import EffectsLibrary
  1. Add the methods you want to override.
  2. Open the main SwiftUI app and set it to use the custom view factory CustomUIFactory.swift when the app launches. Do it by replacing the content of the file with the code below.
//
//  EffectsLibraryStreamChatSwiftUIApp.swift
//  EffectsLibraryStreamChatSwiftUI
//

import SwiftUI
import StreamChat
import StreamChatSwiftUI

@main
struct EffectsLibraryStreamChatSwiftUIApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            // Display the channel list screen
            ChatChannelListView(viewFactory: CustomUIFactory.shared)
        }
    }
}

You can add the snow or any of the effects as an overly on the chat bubbles by implementing the method makeReactionsBackgroundView in the view factory. You can learn about these methods for replacing components in the UI components documentation.

//
//  CustomUIFactory.swift

import SwiftUI
import StreamChat
import StreamChatSwiftUI
import EffectsLibrary

class CustomUIFactory: ViewFactory {
    @Injected(\.chatClient) public var chatClient

    private init() {}

    public static let shared = CustomUIFactory()

   some View {

// Add the Effects Library fireworks, and snow views as overlay on the chat bubbles
    func makeMessageTextView(
        for message: ChatMessage,
        isFirst: Bool,
        availableWidth: CGFloat,
        scrolledId: Binding<String?>) -> some View {
            Text(message.text)
                .padding()
                .messageBubble(for: message, isFirst: isFirst)
                .overlay(
                    BottomRightView {
                        SnowView()                 
                    }
                )
        }    
}

The video below shows the snow effect on the chat bubbles.

Render the Fireworks Particles Inside Chat Bubbles
To show the fireworks inside the chat bubbles, you should implement makeMessageTextView method in CustomUIFactory.swift. The example below adds the fireworks as an overlay on the top-right of the chat bubbles.

// Add the Effects Library fireworks, and snow views as overlay on the chat bubbles
    func makeMessageTextView(
        for message: ChatMessage,
        isFirst: Bool,
        availableWidth: CGFloat,
        scrolledId: Binding<String?>) -> some View {
            Text(message.text)
                .padding()
                .messageBubble(for: message, isFirst: isFirst)
                .overlay(
                    TopRightView {
                        FireworksView()
                            .cornerRadius(16)
                            .offset(x: -4, y: 4)
                            .blendMode(.hardLight)
                    }
                )
        }

The video below shows the fireworks animation on the chat bubbles.

Let the Chat Conversations Background Snow Using Tap-and-Hold Gesture
You have seen how to use and customize the effects library for different use cases. In this final example, you will add the snow animation on the emoji reactions background in Stream Chat using the method makeReactionsBackgroundView in CustomUIFactory.swift. To display the snow animation, you should use a tap-and-hold gesture on the incoming or outgoing message bubbles.

//  CustomUIFactory.swift

import SwiftUI
import StreamChat
import StreamChatSwiftUI
import EffectsLibrary

class CustomUIFactory: ViewFactory {
    @Injected(\.chatClient) public var chatClient

    private init() {}

    public static let shared = CustomUIFactory()

    func makeReactionsBackgroundView(
        currentSnapshot: UIImage,
        popInAnimationInProgress: Bool
    ) -> some View {

        // Add the effects as the background of the emoji reactions
        SnowView()
    }  
}

The video below shows the snow animation on the emoji reactions’ background.

Recap

To conclude, you have learned about integrating particle system animations such as snow, confetti, fireworks, and rain with SwiftUI projects. Not only that. You have discovered how to apply the Effects Library animations to the Stream Chat SwiftUI sample application. Additionally, you have unlocked the advanced customization options of the effects.

Start using the Effects Library today to integrate screen and background animations into your next iOS and SwiftUI projects.

What Next?

You can apply the screen effects and background animations you learned in this tutorial in many different use cases, like chat messaging apps. Check Stream’s SwiftUI Chat SDK to add real-time messaging to your iOS apps. If you are interested in learning more about SwiftUI animations, visit the SwiftUI series on the Stream Developers YouTube channel.