[英]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
可能會導致動畫在中斷時中斷。 將要應用轉換的視圖包裝在VStack
、 HStack
或任何其他容器中是有意義的。
我剛剛放棄了.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.