How to display an animated GIF in SwiftUI

Written by
Rob Bentley

Originally Published on April 24, 2023
Republished on June 26, 2023

I started making a movie app for personal use and wanted it to show an old movie reel countdown GIF.

I wanted the animated GIF to display each time I opened the app while the initial data was loading.

There is a Swift package called FLAnimatedImage that makes it easy to drop in a GIF. To add the swift package in XCode, go to File, then Add Packages.

XCode-File-AddPackages

Enter the link https://github.com/Flipboard/FLAnimatedImage into the search bar on the top right of the window that pops up.

FLAnimatedImage

Click Add Package, then wait for XCode to load it in!

AddPackage-XCode

With the package installed, make a new file and call it GIFView.

You are going to make a UIViewRepresentable, which is a way to display standard Swift code inside a SwiftUI app.

We can make this work in two ways: one would be a file that you add to XCode and another would be with a URL.

To start, we are going to create an enum to pass into the View.

enum URLType 
    case name(String)
    case url(URL)

    var url: URL? {
        switch self {
            case .name(let name):
                 return Bundle.main.url(forResource: name, withExtension: "GIF")
            case .url(let remoteURL):
                 return remoteURL
        }
    }
}

Setting this will tell our View how to load the GIF we want to use.

Now, for our UIViewRepresentable, pass in this code.

 import FLAnimatedImag
 //https://github.com/Flipboard/FLAnimatedImage <-- SPM link for copying later if needed

 struct GIFView: UIViewRepresentable {
     private var type: URLType
     init(type: URLType) {
         self.type = type
     }
     func makeUIView(context: Context) -> UIView {
         let view = UIView(frame: .zero)
         view.addSubview(activityIndicator)
         view.addSubview(imageView)
         imageView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
         imageView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
         activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
         activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        return view
     }

     func updateUIView(_ uiView: UIView, context: Context) {
         activityIndicator.startAnimating()
         guard let url = type.url else { return }
         DispatchQueue.global().async {
             if let data = try? Data(contentsOf: url) {
                 let image = FLAnimatedImage(animatedGIFData: data)
                 DispatchQueue.main.async {
                     activityIndicator.stopAnimating()
                     imageView.animatedImage = image
                 } 
             }
         }
     }

    private let imageView: FLAnimatedImageView = {
        let imageView = FLAnimatedImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        // UNCOMMENT TO ADD ROUNDING TO YOUR VIEW
        // imageView.layer.cornerRadius = 24
        imageView.layer.masksToBounds = true
        return imageView
     }()

     private let activityIndicator: UIActivityIndicatorView = {
         let activityIndicator = UIActivityIndicatorView()
         activityIndicator.translatesAutoresizingMaskIntoConstraints = false
         activityIndicator.color = .systemBlue
         return activityIndicator
     }()
 }

This code block will start by setting the enum type we just made in the init() method, and then load the GIF data into the ImageView. It also provides an activity indicator for GIFs loaded from the web.

To use this in your app, add GIFView in like you would any other SwiftUI View.

Here is a code sample using it in ContentView, showing how to load a GIF from an XCode file:

struct ContentView: View 
    var body: some View {
        ZStack {
            Color.black       
            VStack (alignment: .center) {
                 Spacer()
                 GIFView(type: .name("movieReel"))
                .background(Color.black)
                .frame(maxHeight: 300)
                Spacer()       
            }
        }
    }
}

If you want to load it from a URL, initialize GIFView like this:

GIFView(type: .url(URL(string: "https://i.makeaGIF.com/media/3-28-2018/jLmnQr.GIF")!))

That should be it. Have fun adding GIFs to your app!

Here is a video of it in my app for anyone who isn’t going to code it.

Join our newsletter community

Oh no, there was an error with your email!

Hey, thank you so much for signing up! We've got your address saved, so look forward to an email from us soon. πŸŽ‰

We respect your privacy.