Reputation: 182
I have an array of 5 letters and I need to show each letter sliding in one at a time from left to right with 5 seconds between each, cycling in a continuous loop but showing no more than 5 letters.
Here's what I have so far, but I'm stuck. This doesn't seem like it should be too difficult...what am I missing? Thanks!
import SwiftUI
struct ContentView: View {
@State private var letters = ["S","T","A","R","T"]
@State private var timer = Timer.publish(every: 5, tolerance: 0.5, on: .main, in: .common).autoconnect()
var body: some View {
ZStack {
HStack {
ForEach(self.letters, id:\.self) { letter in
Text(letter)
.font(.custom("Menlo", size: 18))
.fontWeight(.black)
.frame(width: 38, height: 38, alignment: .center)
.background(Color.red)
.clipShape(Circle())
.foregroundColor(.white)
.shadow(radius: 10, x: 10, y: 10)
.transition(AnyTransition.slide)
.animation(Animation.linear(duration: 1).repeatCount(1))
}
}
}
.onReceive(timer) {_ in
//????? should I use this? where and how?
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Upvotes: 2
Views: 1168
Reputation: 154523
In order to animate the characters onto the screen, they need to be offscreen first. That means you need to build up the array of letters your ForEach
is showing.
I made the letters Identifiable
giving them unique id
s so that it wouldn't confuse the first T
in START
with the second T
.
I'm using an offset
for animation
instead of slide
. The arriving
property of a letter is used to decide the direction of the offset
.
struct Letter: Identifiable {
let letter: String
var arriving: Bool
let id = UUID()
}
struct ContentView: View {
@State private var start = [" ","S","T","A","R","T"].map { Letter(letter: $0, arriving: true) }
@State private var letters = [Letter]()
@State private var timer = Timer.publish(every: 2, tolerance: 0.5, on: .main, in: .common).autoconnect()
var body: some View {
ZStack {
HStack {
ForEach(self.letters) { letter in
Text(letter.letter)
.font(.custom("Menlo", size: 18))
.fontWeight(.black)
.frame(width: 38, height: 38, alignment: .center)
.background(Color.red)
.clipShape(Circle())
.foregroundColor(.white)
.shadow(radius: 10, x: 10, y: 10)
.transition(AnyTransition.offset(x: letter.arriving ? -250 : 250))
.animation(Animation.linear(duration: 1).repeatCount(1))
}
}
}
.onReceive(timer) {_ in
print("TIMER")
var letter = start.removeLast()
letter.arriving = true
letters.indices.forEach { idx in letters[idx].arriving = false }
letters = [letter] + letters
if letters.count > 5 {
let last = letters.removeLast()
start = [last] + start
}
}
}
}
Upvotes: 2