I have an array of string and of course when the view appears, the ForEach shows all the items at once, but I would like to show one item at a time, i think i should do it using an animation but i don't know how to go on...
This is the effect i'm trying to achieve:
This is my simple code:
struct ContentView: View {
let correctNames = ["Steve", "Bill", "Elon", "Paul"]
var body: some View {
VStack {
ForEach(correctNames, id: \.self) { name in
Text("\(name)")
.font(.largeTitle)
.bold()
}
}
}
}
CodePudding user response:
Simple approach.
Use a timer and a counter. Increment the counter every second and show the items 0 to counter animated. If the counter reaches the size of the array cancel the timer.
struct ContentView: View {
let correctNames = ["Steve", "Bill", "Elon", "Paul"]
let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
@State private var counter = 0
var body: some View {
VStack {
ForEach(0...counter, id: \.self) { index in
Text(correctNames[index])
.font(.largeTitle)
.bold()
}
}
.onReceive(timer) { _ in
withAnimation {
if counter < correctNames.count - 1 {
counter = counter 1
} else {
timer.upstream.connect().cancel()
}
}
}
}
}
CodePudding user response:
Here's a different take. Use .opacity()
to hide/show the names, and give each view an increasing delay
. When animating
is toggled with onAppear
, the views will show one by one.
struct ContentView: View {
@State private var animating = false
let correctNames = ["Steve", "Bill", "Elon", "Paul"]
var body: some View {
VStack {
ForEach(0..<correctNames.count, id: \.self) { index in
Text("\(correctNames[index])")
.font(.largeTitle)
.bold()
.opacity(animating ? 1 : 0)
.animation(.default.delay(Double(index)), value: animating)
}
}
.onAppear { animating.toggle() }
}
}
If you want to make the fade in longer, replace the .animation()
line with:
.animation(.easeIn(duration: 0.9).delay(Double(index)), value: animating)
To increase or decrease the time between names, multiply Double(index)
by the number of seconds you want.