Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 782
Mehdi Avatar asked Jun 23 '19 09:06

Mehdi


People also ask

How do I animate a view in SwiftUI?

If you want a SwiftUI view to start animating as soon as it appears, you should use the onAppear() modifier to attach an animation.

How do I add animations to SwiftUI?

SwiftUI has built-in support for animations with its animation() modifier. To use this modifier, place it after any other modifiers for your views, tell it what kind of animation you want, and also make sure you attach it to a particular value so the animation triggers only when that specific value changes.


1 Answers

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.

like image 187
Nuno Gonçalves Avatar answered Nov 09 '22 23:11

Nuno Gonçalves