CS0521
CS0521

Reputation: 182

How do I animate an image to continuously move across the screen?

This code shows the general behavior I'm trying to achieve, but how can I make this continuous so there's no apparent end to the image, with no gaps of white space and a smooth transition? AND - isn't there a better way to do this???

Thanks!

import SwiftUI

struct ContentView: View {
    @State private var xVal: CGFloat = 0.0
    @State private var timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect()

    var body: some View {
        ZStack {
            Image("game_background_2")  //image attached
                .aspectRatio(contentMode: .fit)
                .offset(x: xVal, y: 0)
                .transition(.slide)
                .padding()
                .onReceive(timer) {_ in
                    xVal += 2
                    if xVal == 800 { xVal = 0 }
                }
        }
    }
}

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

enter image description here

Upvotes: 1

Views: 3032

Answers (1)

nicksarno
nicksarno

Reputation: 4245

Here's a simple approach that could work. First use a GeometryReader to set the frame of the screen. Then add an HStack with 2 images inside. The first image is full size and the 2nd image is limited to the width of the screen. Finally, animate the HStack to move from the .trailing to the .leading edge of the screen frame. We set the animation .repeatForever so that it continues loops and autoReverses: false so that it restarts. When it restarts, however, it should be seamless because the restart position is identical to the 2nd image.

struct ImageBackgroundView: View {
    
    @State var animate: Bool = false
    let animation: Animation = Animation.linear(duration: 10.0).repeatForever(autoreverses: false)
    
    var body: some View {
        GeometryReader { geo in
            HStack(spacing: -1) {
                Image("game_background_2")
                    .aspectRatio(contentMode: .fit)

                Image("game_background_2")
                    .aspectRatio(contentMode: .fit)
                    .frame(width: geo.size.width, alignment: .leading)
            }
            .frame(width: geo.size.width, height: geo.size.height,
                   alignment: animate ? .trailing : .leading)
        }
        .ignoresSafeArea()
        .onAppear {
            withAnimation(animation) {
                animate.toggle()
            }
        }
    }
}

Upvotes: 5

Related Questions