首页 > 解决方案 > ScrollView 中的初始 SwiftUI 动画

问题描述

在我的应用程序中ScrollView,我有一个VStack. 有VStack一个animation修饰符。它还有一个带有transition修饰符的条件视图。过渡有效。但是,当视图首次出现时,内容会以 0 的起始宽度放大。您可以在下面视频的绿色边框上看到这一点。这只发生在 theVStack内部ScrollViewVStack具有animation修饰符的情况下。

我尝试了其他不同的方法,例如设置 afixedSize或设置animation(nil),但我无法让它工作。

我不在乎开头是否有动画,或者视图是否转换到屏幕上。但我绝对不想要一开始的糟糕动画。当我单击按钮时,TextButton都应该动画。

我还使用以下简化代码测试了这种行为。

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        ScrollView {
            VStack(spacing: 32) {
                if self.viewModel.shouldShowText {
                    Text("Hello, World! This is a some text.")
                        .transition(
                            AnyTransition
                                .move(edge: .top)
                                .combined(
                                    with:
                                        .offset(
                                            .init(width: 0, height: -100)
                                        )
                                )
                        )
                }

                Button(
                    action: {
                        self.viewModel.didSelectButton()
                    },
                    label: {
                        Text("Button")
                            .font(.largeTitle)
                    }
                )
            }
            .border(Color.green)
            .animation(.easeInOut(duration: 5))
            .border(Color.red)

            HStack { Spacer() }
        }
        .border(Color.blue)
    }
}

class ViewModel: ObservableObject {
    @Published private var number: Int = 0

    var shouldShowText: Bool {
        return self.number % 2 == 0
    }

    func didSelectButton() {
        self.number += 1
    }
}

标签: swiftuiswiftui-animation

解决方案


它适用于 Xcode 12 / iOS 14(以及独立和 in NavigationView),所以我认为它是以前版本中的 SwiftUI 错误。

无论如何,尝试通过值激活动画,如下所示(经过测试和工作)

  // ... other code
}
.border(Color.green)
.animation(.easeInOut(duration: 5), value: viewModel.number)   // << here !!
.border(Color.red)

对于这项工作,它需要提供已发布的属性以供观察

class BlockViewModel: ObservableObject {
    @Published var number: Int = 0             // << here !!
 
    // ... other code

推荐阅读