iosswiftxcodeanimationswiftui

How to animate a sequence of images using SwiftUI?


How can I animate a sequence of images (say Frame-1.png all the to Frame-6) using the SwiftUI framework?

I've tried creating an array of "images". Then I assigned the UIImage.animatedImage(with: images, duration: 1.0) method to a variable called "animatedImage" finally I tried Image(uiImage: animatedImage) in "body" of "ContentView.swift"


var images: [UIImage]! = [UIImage(named: "Sequence/frame-1")!,
                          UIImage(named: "Sequence/frame-2")!,
                          UIImage(named: "Sequence/frame-3")!,
                          UIImage(named: "Sequence/frame-4")!,
                          UIImage(named: "Sequence/frame-5")!,
                          UIImage(named: "Sequence/frame-6")!
]

let animatedImage : UIImage! = UIImage.animatedImage(with: images, duration: 1.0)

//////Then in the ContentView.swift I've tried this code:

struct ContentView : View {
    var body: some View {

        Image(uiImage: animatedImage)

    }
}

when I run the program it just shows the firs frame, but I expected an animation of the frames


Solution

  • The accepted answer works very well, with the unfortunate issues mentioned by bhagyash ingale which makes it very hard to use. It would be useful if the specific methods of Image could be reused via protocols or something. I have a very poor and maybe huge cannon for a fly solution for this, maybe it'll be easier in time but for now...

    class LoadingTimer {
    
        let publisher = Timer.publish(every: 0.1, on: .main, in: .default)
        private var timerCancellable: Cancellable?
    
        func start() {
            self.timerCancellable = publisher.connect()
        }
    
        func cancel() {
            self.timerCancellable?.cancel()
        }
    }
    
    struct LoadingView: View {
    
        @State private var index = 0
    
        private let images = (0...7).map { UIImage(named: "Image-\($0).jpg")! }
        private var timer = LoadingTimer()
    
        var body: some View {
    
            return Image(uiImage: images[index])
                .resizable()
                .frame(width: 100, height: 100, alignment: .center)
                .onReceive(
                    timer.publisher,
                    perform: { _ in
                        self.index = self.index + 1
                        if self.index >= 7 { self.index = 0 }
                    }
                )
                .onAppear { self.timer.start() }
                .onDisappear { self.timer.cancel() }
        }
    }
    

    I don't like this but it gets the job done and relies on a Image.