SwiftUI 动画彼此不同步

问题描述 投票:0回答:2

我正在尝试在不同的视图上为一些不同的属性设置动画。这些动画都使用相同的

Animation
(具有相同的持续时间),并且它们都由相同的属性驱动。然而,我发现它们很快就变得不同步,我不明白为什么。这是我的代码:

import SwiftUI

struct ContentView: View {
    @State var isAnimating = false

    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 8, style: .continuous)
                .fill(Color.yellow)
                .offset(x: isAnimating ? -30 : 0)
                .rotationEffect(isAnimating ? .degrees(-10) : .zero)

            RoundedRectangle(cornerRadius: 8, style: .continuous)
                .fill(Color.green.opacity(0.5))
                .offset(x: isAnimating ? 30 : 0)
                .rotationEffect(isAnimating ? .degrees(10) : .zero)

            RoundedRectangle(cornerRadius: 8, style: .continuous)
                .fill(Color.red)
                .scaleEffect(isAnimating ? 1.1 : 1)
        }
        .frame(width: 100, height: 100)
        .padding()
        .onAppear {
            let animation = Animation.bouncy(duration: 0.5)
                .repeatForever(autoreverses: true)

            withAnimation(animation) {
                isAnimating = true
            }
        }
    }
}

#Preview {
    ContentView()
}

我发现的唯一解决方法是使用与

Animation
不同的
Animation.bouncy
,例如
Animation.linear
Animation.easeInOut
。在这种情况下,动画全部保持同步。这让我相信这与
Animation.bouncy
有关(其他弹性动画也存在同样的问题,例如
Animation.spring
)。

此问题出现在 SwiftUI 预览版、设备上和 iOS 模拟器上(全部使用截至撰写时的最新软件:iOS 17.4、Xcode 15.3)。

视频:https://imgur.com/a/btVESSG

ios animation swiftui
2个回答
0
投票

解决方法是与

Animation.interpolatingSpring(duration: 0.5)

由于

.bouncy
是自定义的弹簧动画,因此您可以使用interpolatingSpring并达到所需的结果

根据文档:

插值弹簧动画,使用阻尼弹簧模型生成 [0, 1] 范围内的值,然后使用这些值在动画属性的 [from, to] 范围内进行插值。通过添加每个动画的效果来保持重叠动画的速度。


0
投票

这对我来说看起来像是一个错误。涉及旋转和偏移的动画不考虑动画持续时间,并且在结束时有延迟。延迟几乎与动画本身一样长(如果给动画更长的持续时间,延迟会更明显)。

作为解决方法,您可以使用

PhaseAnimator 
将向前和向后动画链接在一起,而不是使用
.repeatForever(autoreverses: true)

struct ContentView: View {
    var body: some View {
        PhaseAnimator([false, true]) { flag in
            ZStack {
                RoundedRectangle(cornerRadius: 8, style: .continuous)
                    .fill(Color.yellow)
                    .offset(x: flag ? -30 : 0)
                    .rotationEffect(flag ? .degrees(-10) : .zero)

                RoundedRectangle(cornerRadius: 8, style: .continuous)
                    .fill(Color.green.opacity(0.5))
                    .offset(x: flag ? 30 : 0)
                    .rotationEffect(flag ? .degrees(10) : .zero)

                RoundedRectangle(cornerRadius: 8, style: .continuous)
                    .fill(Color.red)
                    .scaleEffect(flag ? 1.1 : 1)
            }
            .animation(.bouncy(duration: 0.5), value: flag)
        }
        .frame(width: 100, height: 100)
        .padding()
    }
}

Animation

© www.soinside.com 2019 - 2024. All rights reserved.