Unexpected behaviour SwiftUI

Hello there,

I want to create letters "rain" effect in SwiftUI, actually in this code, I would like letters to start from the top and once they reach the end of the screen, be randomly placed again all over the X axis at the top of the screen (red part in the picture) and fall linear, but unfortunately these letters make strange movements, and I don't understand why they react this way I tried to change the offset values, but it didn't work at all! :(

import SwiftUI

struct ContentView: View {
    
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    let letters: [String] = ["A", "B", "C", "D"]
    @State private var yOffset: CGFloat = 0.0
    
    var body: some View {
        VStack {
            ForEach(letters, id: \.self) { letter in
                
                Text(letter)
                    .padding()
                    .font(.largeTitle)
                    .position(x: CGFloat.random(in: 0...screenWidth))
                    .offset(x: 0, y: yOffset)
                    .animation(Animation.linear(duration: 5.0).repeatForever(autoreverses: false))
                    .onAppear {
                        yOffset = screenHeight - 90
                    }
            }
            Spacer()
        }
    }
}

Please, If anyone knows how to fix this issue, help me.

When you test with a single letter, you see the random is not re executed when animation completes.

You should implement a completion handler and call again random here.

See here how to achieve this:

  • https://www.avanderlee.com/swiftui/withanimation-completion-callback/

or

  • https://medium.com/geekculture/swiftui-animation-completion-b6f0d167159e

I've tried this way, but actually it stops on a random point in the X-axis.
I really can't understand how to figure out this.

import SwiftUI

struct ContentView: View {
    
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    let letters: [String] = ["A"]
    @State private var xOffset: CGFloat = 0.0
    @State private var yOffset: CGFloat = 0.0
    @State var animation = false
    
    var body: some View {
            ForEach(letters, id: \.self) { letter in
                
                Text(letter)
                    .padding()
                    .font(.largeTitle)
                    .offset(x: xOffset, y: yOffset)
                    .animation(Animation.linear(duration: 1.0).repeatForever(autoreverses: false))
                    .onAppear {
                        yOffset = CGFloat.random(in: 0...screenHeight)
                        
                    }
            }   
        
        Spacer()
    }
}
Unexpected behaviour SwiftUI
 
 
Q