过渡动画在SwiftUI中不起作用

sup*_*cio 7 animation ios swift swiftui

我正在尝试创建一个非常简单的过渡动画,通过点击一个按钮在屏幕中央显示/隐藏一条消息:

struct ContentView: View {
    @State private var showMessage = false

    var body: some View {
        ZStack {
            Color.yellow

            VStack {
                Spacer()
                Button(action: {
                    withAnimation(.easeOut(duration: 3)) {
                        self.showMessage.toggle()
                    }
                }) {
                    Text("SHOW MESSAGE")
                }
            }

            if showMessage {
                Text("HELLO WORLD!")
                    .transition(.opacity)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

根据.transition(.opacity)动画文件

插入时从不透明过渡到不透明,移除时从不透明过渡到透明。

消息应该在showMessagestate属性为true 时淡入,在state属性为false时淡出。就我而言,这是不正确的。该消息以淡入淡出的动画显示,但它完全没有动画隐藏。有任何想法吗?

编辑:请参阅下面的gif从模拟器中获取的结果。

在此处输入图片说明

Pbk*_*Pbk 51

我的发现是不透明度转换并不总是有效。(但幻灯片与 .animation 结合使用也可以。)

.transition(.opacity) //does not always work
Run Code Online (Sandbox Code Playgroud)

如果我将其编写为自定义动画,它确实有效:

.transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.2))) 
.zIndex(1)
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,截至目前(iOS 14 / XCode 12)不需要 zIdex (5认同)
  • 我可以确认这有效。奇怪的是 SwiftUI 上的某些实现不能一致地工作 (4认同)
  • 这实际上非常有趣 - 如果您在代码中的其他地方使用“withAnimation()”,并且对于仅使用“.opacity”的过渡,您将获得单向动画 - 仅在移出层次结构时起作用。当您按照这个答案告诉您使用它时,它是双向的。这是一个错误,不是吗? (4认同)
  • 哇,有人为此提交了雷达吗?Swiftui 中的转换是如此错误 smh (4认同)
  • 这应该是答案。有这方面的文档吗?看起来像一个错误。 (2认同)

Saj*_*avi 9

我在 swiftUI_preview 中发现了一个动画错误。当您在代码中使用过渡动画并希望在 SwiftUI_preview 中看到它时,它不会显示动画或仅显示某个视图随动画消失的时间。为了解决这个问题,你只需要在 VStack 的预览中添加你的视图。像这样 :

struct test_UI: View {
    @State var isShowSideBar = false
    var body: some View {
        ZStack {
            Button("ShowMenu") {
                withAnimation {
                    isShowSideBar.toggle()
                }
                
            }
            if isShowSideBar {
                SideBarView()
                    .transition(.slide)
            }
        }
    }
}
        struct SomeView_Previews: PreviewProvider {
        static var previews: some View {
            VStack {
               SomeView()
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

在此之后,所有动画都会发生。

  • 这真的非常非常奇怪,但它确实有效!谢谢。 (5认同)
  • 极好的。Xcode 15 已经出来了,这个 bug 仍然存在。 (3认同)
  • 现在已经 2022 年底了,这个 bug 仍然存在。谢谢! (2认同)

テッド*_*テッド 8

我相信这是画布的问题。今天早上我正在玩转场,虽然在画布上不起作用,但它们似乎在模拟器中工作。试一试吧。我已向 Apple 报告了该错误。

  • 这正是我的问题!我想知道代码出了什么问题。太感谢了! (2认同)

小智 6

问题是,当视图在ZStack中来来往往时,它们的“ zIndex”不会保持不变。发生的事情是,当“ showMessage”从true变为false时,带有“ Hello World”文本的VStack被放置在堆栈的底部,黄色立即被绘制在其顶部。它实际上正在逐渐消失,但是它在黄色后面显示,因此您看不到它。

要解决此问题,您需要为堆栈中的每个视图明确指定“ zIndex”,以使它们始终保持不变-如下所示:

struct ContentView: View {
@State private var showMessage = false

var body: some View {
    ZStack {
        Color.yellow.zIndex(0)

        VStack {
            Spacer()
            Button(action: {
                withAnimation(.easeOut(duration: 3)) {
                    self.showMessage.toggle()
                }
            }) {
                Text("SHOW MESSAGE")
            }
        }.zIndex(1)

        if showMessage {
            Text("HELLO WORLD!")
                .transition(.opacity)
                .zIndex(2)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

}


kon*_*iki 5

我更喜欢 Scott Gribben 的答案(见下文),但由于我无法删除这个答案(由于绿色对勾),我将保留原始答案不变。我会争辩说,我确实认为这是一个错误。人们会期望 zIndex 由代码中出现的顺序隐式分配。


要解决这个问题,您可以将 if 语句嵌入到 VStack 中。

struct ContentView: View {
    @State private var showMessage = false

    var body: some View {
        ZStack {
            Color.yellow

            VStack {
                Spacer()
                Button(action: {
                    withAnimation(.easeOut(duration: 3)) {
                        self.showMessage.toggle()
                    }
                }) {
                    Text("SHOW MESSAGE")
                }
            }

            VStack {
                if showMessage {
                    Text("HELLO WORLD!")
                        .transition(.opacity)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)