簡體   English   中英

過渡動畫在 SwiftUI 中不起作用

[英]Transition animation not working in 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 中的結果。

在此處輸入圖像描述

問題是當視圖在 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)
        }
    }
}

}

我的發現是不透明度轉換並不總是有效。 (但幻燈片與 .animation 結合使用會起作用..)

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

如果我將其編寫為自定義動畫,它確實有效:

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

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

在此之后,所有動畫都會發生。

我相信這是畫布的問題。 今天早上我在玩轉場,雖然不在畫布上工作,但它們似乎在模擬器中工作。 試試看。 我已經向 Apple 報告了這個錯誤。

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

zIndex可能會導致動畫在中斷時中斷。 將要應用轉換的視圖包裝在VStackHStack或任何其他容器中是有意義的。

我剛剛放棄了.transition。 它只是不工作。 我改為動畫視圖的偏移,更可靠:

首先我為偏移量創建一個狀態變量:

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

下面的代碼應該可以工作。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM