在 SwiftUI 中连续重复操作

Repeating Action Continuously In SwiftUI

如何使文本字段等元素连续放大然后缩小?

我有这个:

struct ContentView : View {
    @State var size:Double = 0.5

    var body: some View { 
        ZStack {
            Text("Hello!")
                 .padding()
                 .scaleEffect(size)
        }
    }
}

我知道我需要增加大小然后在某种循环中减少它,但在 SwiftUI 中无法完成以下操作:

while true {

  self.size += 0.8
  sleep(0.2)
  self.size -= 0.8

}

一个可能的解决方案是使用(重复,auto-reversing)动画:

struct ContentView : View {
    @State var size: CGFloat = 0.5
    
    var repeatingAnimation: Animation {
        Animation
            .easeInOut(duration: 2) //.easeIn, .easyOut, .linear, etc...
            .repeatForever()
    }

    var body: some View {
        Text("Hello!")
            .padding()
            .scaleEffect(size)
            .onAppear() {
                withAnimation(self.repeatingAnimation) { self.size = 1.3 }
        }
    }
}

最好的方法是创建单独的动画结构并配置您需要的所有选项(这样您的代码会更紧凑)。

为了使其更加清晰和合乎逻辑,请使用@State 属性 isAnimating。您将能够停止动画并再次恢复并了解动画何时进行。

    @State private var isAnimating = false

    var foreverAnimation: Animation {
        Animation.linear(duration: 0.3)
        .repeatForever()
    }

    var body: some View {

        Text("Hello")
            .scaleEffect(isAnimating ? 1.5 : 1)
            .animation(foreverAnimation)
            .onAppear {
                self.isAnimating = true
        }
}

Animation.basic 已弃用。基本动画现在以其曲线类型命名:如线性等:

var foreverAnimation: Animation {
        Animation.linear(duration: 0.3)
        .repeatForever()
 }

来源: https://forums.swift.org/t/swiftui-animation-basic-duration-curve-deprecated/27076

在 if 语句中使用时,在视图上使用重复动画会出现奇怪的行为。

如果你想做:

if something {
    BlinkingView()
}

使用带有动画修饰符的转换,否则即使 something 设置为 false,视图仍停留在屏幕上。

我进行此扩展以显示重复从一种状态到另一种状态并返回的视图:

extension AnyTransition {
    static func repeating<T: ViewModifier>(from: T, to: T, duration: Double = 1) -> AnyTransition {
       .asymmetric(
            insertion: AnyTransition
                .modifier(active: from, identity: to)
                .animation(Animation.easeInOut(duration: duration).repeatForever())
                .combined(with: .opacity), 
            removal: .opacity
        )
    }
}

这使得视图随着 AnyTransition.opacity 出现和消失,并且在显示时它会在 fromto 状态之间切换,延迟 duration

用法示例:

struct Opacity: ViewModifier {
    private let opacity: Double
    init(_ opacity: Double) {
        self.opacity = opacity
    }

    func body(content: Content) -> some View {
        content.opacity(opacity)
    }
}

struct ContentView: View {
    @State var showBlinkingView: Bool = false

    var body: some View {
        VStack {
            if showBlinkingView {
                Text("I am blinking")
                    .transition(.repeating(from: Opacity(0.3), to: Opacity(0.7)))
            }
            Spacer()
            Button(action: {
                self.showBlinkingView.toggle()
            }, label: {
                Text("Toggle blinking view")
            })
        }.padding(.vertical, 50)
    }
}

编辑:

当显示条件为真时,转换不会开始。为了解决这个问题,我确实切换了超级视图出现的条件(在我的例子中是 VStack):

.onAppear {
    if self.showBlinkingView {
        self.showBlinkingView.toggle()
        DispatchQueue.main.async {
            self.showBlinkingView.toggle()
        }
    }
}