延迟的SwiftUI动画

时间:2020-09-15 01:09:10

标签: swiftui

我有一个由5个字母组成的数组,我需要显示每个字母一次从左向右滑动,每个字母之间的间隔为5秒,以一个连续的循环循环,但最多显示5个字母。

到目前为止,这就是我所拥有的,但是我被困住了。这似乎并不难,我想念什么?谢谢!

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()
    }
}

1 个答案:

答案 0 :(得分:0)

为了使角色在屏幕上动起来,需要先将它们移出屏幕。这意味着您需要建立ForEach显示的字母数组。

我将字母Identifiable赋予了它们唯一的id,以便不会将T中的第一个START与第二个T混淆。

我为offset使用了animation而不是slide。字母的arriving属性用于确定offset的方向。

enter image description here

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
            }
        }
    }
}