过渡动画在SwiftUI中不起作用

时间:2019-08-30 16:08:24

标签: ios swift animation 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)
            }
        }
    }
}

根据.transition(.opacity)动画的文档

  

插入时从透明过渡到不透明,以及从不透明过渡   清除后变为透明。

showMessage状态属性为true时,消息应淡入,而当其为false时,消息应淡出。就我而言,这是不正确的。该消息以淡入淡出的动画显示,但它完全没有动画隐藏。有什么想法吗?

编辑:在下面的gif中,从模拟器中查看结果。

enter image description here

6 个答案:

答案 0 :(得分:31)

我的发现是不透明过渡并不总是有效。 (不过,将幻灯片与.animation结合使用是可以的。)

    .transition(.opacity) //does not always work

如果我将其编写为自定义动画,它将起作用:

    .transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.2))) 
    .zIndex(1)

答案 1 :(得分: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)
        }
    }
}

}

答案 2 :(得分:2)

我更喜欢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)
                }
            }
        }
    }
}

答案 3 :(得分:1)

我认为这是画布的问题。我今天早上正在玩转场游戏,虽然它们不能在画布上工作,但它们确实可以在模拟器中工作。试试看。我已经将该错误报告给了Apple。

答案 4 :(得分:0)

zIndex可能会导致动画在中断时被破坏。在VStackHStack中包装您要应用转换的视图,否则其他容器都将是有意义的。

答案 5 :(得分:0)

我在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()
            }
        }
    }

此后,所有动画都将发生。