SwiftUI animation: Как сработать с повторением анимации с задержкой - PullRequest
1 голос
/ 25 марта 2020

Попытка реализовать следующую анимацию в SwiftUI и найти ее совершенно невозможной:

enter image description here

Суммировать эффект: повторяющийся импульс, анимирующий каждый сегмент с шаткой задержкой. Для каждого сегмента:

  • Начиная с непрозрачности = 0,5, масштаб = 1
  • Анимировать до непрозрачности = 1,0, масштаб = 1,3
  • Кривая анимации начинается быстро с более длительное замедление

Кроме того, между каждым «импульсом» есть задержка.

Самое близкое, что мне удалось сделать с SwiftUI, - это непрерывно повторяющаяся анимация. используя модификатор .repeatForever. (Код ниже. Пока игнорируйте несоответствие во времени.)

Как добавить задержку между каждым l oop анимации?

Вот результат моего кода ниже:

enter image description here

import SwiftUI

struct ArrowShape : Shape {

    func path(in rect: CGRect) -> Path {
        var path = Path()

        path.move(to: CGPoint(x: 0, y: 0))
        path.addLine(to: CGPoint(x: rect.size.width, y: rect.size.height/2.0))
        path.addLine(to: CGPoint(x: 0, y: rect.size.height))

        return path
    }
}

struct Arrows: View {
    private let arrowCount = 3

    @State var scale:CGFloat = 1.0
    @State var fade:Double = 0.5

    var body: some View {

        ZStack {
            Color(red: 29.0/255.0, green: 161.0/255.0, blue: 224.0/255.0).edgesIgnoringSafeArea(.all)

            HStack{
                ForEach(0..<self.arrowCount) { i in
                    ArrowShape()
                        .stroke(style: StrokeStyle(lineWidth: CGFloat(10),
                                                  lineCap: .round,
                                                  lineJoin: .round ))
                        .foregroundColor(Color.white)
                        .aspectRatio(CGSize(width: 28, height: 70), contentMode: .fit)
                        .frame(maxWidth: 20)
                        .animation(nil)
                        .opacity(self.fade)
                        .scaleEffect(self.scale)
                        .animation(
                            Animation.easeOut(duration: 0.8)
                            .repeatForever(autoreverses: true)
                            .delay(0.2 * Double(i))
                        )
                }
            }

            .onAppear() {
                self.scale = 1.2
                self.fade = 1.0
            }
        }
    }
}



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

1 Ответ

1 голос
/ 25 марта 2020

Я думаю, что вы можете реализовать это, используя Timer и DispatchQueue, попробуйте это и убедитесь, что оно работает, как вы хотите, или нет

struct Arrows: View {
    private let arrowCount = 3

    let timer = Timer.publish(every: 2, on: .main, in: .common).autoconnect()

    @State var scale:CGFloat = 1.0
    @State var fade:Double = 0.5

    var body: some View {

        ZStack {
            Color(red: 29.0/255.0, green: 161.0/255.0, blue: 224.0/255.0).edgesIgnoringSafeArea(.all)

            HStack{
                ForEach(0..<self.arrowCount) { i in
                    ArrowShape()
                        .stroke(style: StrokeStyle(lineWidth: CGFloat(10),
                                                  lineCap: .round,
                                                  lineJoin: .round ))
                        .foregroundColor(Color.white)
                        .aspectRatio(CGSize(width: 28, height: 70), contentMode: .fit)
                        .frame(maxWidth: 20)
                        .animation(nil)
                        .opacity(self.fade)
                        .scaleEffect(self.scale)
                        .animation(
                            Animation.easeOut(duration: 0.5)
                            //.repeatForever(autoreverses: true)
                            .repeatCount(1, autoreverses: true)
                            .delay(0.2 * Double(i))
                        )
                }.onReceive(self.timer) { _ in
                     self.scale = self.scale > 1 ?  1 : 1.2
                     self.fade = self.fade > 0.5 ? 0.5 : 1.0
                     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                                self.scale = 1
                                self.fade = 0.5
                            }
                    }
            }
        }
    }
}
...