ios SwiftUI中的过渡动画不起作用

bxpogfeg  于 2022-12-05  发布在  iOS
关注(0)|答案(8)|浏览(366)

I'm trying to create a really simple transition animation that shows/hides a message in the center of the screen by tapping on a button:

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)
            }
        }
    }
}

According to the documentation of the .transition(.opacity) animation
A transition from transparent to opaque on insertion, and from opaque to transparent on removal.
the message should fade in when the showMessage state property becomes true and fade out when it becomes false. This is not true in my case. The message shows up with a fade animation, but it hides with no animation at all. Any ideas?

EDIT: See the result in the gif below taken from the simulator.

8cdiaqws

8cdiaqws1#

问题是,当视图在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)
            }
        }
    }
}
wecizke3

wecizke32#

我的发现是,不透明过渡并不总是工作。(然而,幻灯片结合一个。动画将工作。)

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

如果我把它写成一个自定义动画,它就可以工作:

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

wqsoz72f3#

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

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

dgjrabp2

dgjrabp24#

我认为这是画布的问题。今天早上我在玩过渡,虽然在画布上不起作用,但在模拟器中似乎起作用了。给予看。我已经向苹果报告了这个错误。

j2qf4p5b

j2qf4p5b5#

我更喜欢Scott Gribben的答案(见下文),但由于我不能删除这个答案(因为绿色的复选标记),我将保留原始答案不变。不过我认为这是一个bug。人们会期望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)
                }
            }
        }
    }
}
mi7gmzs6

mi7gmzs66#

zIndex可能会导致动画在中断时中断。请将您要套用转换的检视 Package 在VStackHStack或任何其他容器中。

mw3dktmi

mw3dktmi7#

我放弃了. transition。它不起作用。我改为动画视图的偏移,更可靠:
首先,我创建了一个状态变量offset:

@State private var offset: CGFloat = 200

第二步,我将VStack的偏移量设置为它,然后在.onAppear()中,用动画将偏移量改回0:

VStack{
            Spacer()
            HStack{
                Spacer()
                Image("MyImage")
            }
        }
        .offset(x: offset)
        .onAppear {
            withAnimation(.easeOut(duration: 2.5)) {
                offset = 0
            }
        }
w6mmgewl

w6mmgewl8#

下面的代码应该可以工作。

import SwiftUI

struct SwiftUITest: View {
    
    @State private var isAnimated:Bool = false
  
    var body: some View {
        ZStack(alignment:.bottom) {
            VStack{
                Spacer()
                Button("Slide View"){
                    withAnimation(.easeInOut) {
                        isAnimated.toggle()
                    }
                    
                }
                Spacer()
                Spacer()
           
            }
            if isAnimated {
                RoundedRectangle(cornerRadius: 16).frame(height: UIScreen.main.bounds.height/2)
                    .transition(.slide)

            }
            
            
        }.ignoresSafeArea()
    }
}

struct SwiftUITest_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            SwiftUITest()
        }
    }
}

相关问题