文章目錄
- 前言
- 簡單示例
- 動畫視圖修飾符
- 使用多個可動畫屬性
- 使用 ViewBuilder
- 總結
前言
從一開始,動畫就是 SwiftUI 最強大的功能之一。你可以在 SwiftUI 中快速構建流暢的動畫。唯一的缺點是每當我們需要運行多步動畫或將動畫范圍限定到視圖層次結構的特定部分時,我們如何控制動畫。
簡單示例
讓我們從一個簡單的示例開始,展示我們舊方法的一些缺點,這些方法用于在 SwiftUI 中驅動動畫。
struct ContentView: View {@State private var isHidden = falsevar body: some View {VStack {Button("Animate") {isHidden.toggle()}HugeView().opacity(isHidden ? 0.0 : 1.0)AnotherHugeView()}.animation(.default)}
}
如上例所示,我們有一個包含按鈕和兩個視圖的視圖層次結構,這些視圖放置在垂直堆棧中。我們將動畫視圖修飾符附加到整個堆棧,以動畫堆棧內的任何更改。
當我們按下按鈕時,堆棧會動畫顯示內部的任何更改。但是,動畫視圖修飾符不連接到 isHidden 屬性,這意味著它將動畫顯示可能發生的任何更改。其中一些更改可能是意外的,比如環境值的變化。
動畫視圖修飾符
我們可以通過使用動畫視圖修飾符的另一個版本來消除意外動畫,在這個版本中,我們可以綁定到特定值,并且僅在值更改時進行動畫處理。
struct ContentView: View {@State private var isHidden = falsevar body: some View {VStack {Button("Animate") {isHidden.toggle()}HugeView().opacity(isHidden ? 0.0 : 1.0)AnotherHugeView()}.animation(.default, value: isHidden)}
}
在上面的示例中,我們使用了帶有 value 參數的動畫視圖修飾符。它允許我們將動畫范圍限定為單個值,并僅在與特定值相關的更改時執行動畫。在這種情況下,我們沒有任何意外的動畫。
使用多個可動畫屬性
如果我們有多個可動畫屬性怎么辦?
在這種情況下,我們必須為每個可動畫屬性附加一個動畫修飾符。這個解決方案非常有效,但在人體工程學方面有一個缺點。
struct ContentView: View {@State private var firstStep = false@State private var secondStep = falsevar body: some View {VStack {Button("Animate") {Task {firstStep.toggle()try? await Task.sleep(nanoseconds: 3_000_000_000)secondStep.toggle()}}// 其他視圖在這里SomeView().opacity(firstStep ? 1.0 : 0.0).blur(radius: secondStep ? 0 : 20.0)}.animation(.default, value: firstStep).animation(.default, value: secondStep)}
}
幸運的是,SwiftUI 引入了動畫視圖修飾符的一個新變體,允許我們使用 ViewBuilder 閉包來限定動畫的范圍。
struct ContentView: View {@State private var firstStep = false@State private var secondStep = falsevar body: some View {VStack {Button("Animate") {Task {firstStep.toggle()try? await Task.sleep(nanoseconds: 1_000_000_000)secondStep.toggle()}}// 其他視圖在這里SomeView().animation(.default) { content incontent.opacity(firstStep ? 1.0 : 0.0).blur(radius: secondStep ? 0 : 20.0)}}}
}
如上例所示,我們使用動畫視圖修飾符,提供我們需要的動畫類型和一個 ViewBuilder 閉包,在這個動畫中應用。動畫僅在提供的 ViewBuilder 閉包的上下文中工作,不會擴展到其他任何地方。
使用 ViewBuilder
作為起點,ViewBuilder 閉包提供一個參數,用于占位視圖,在其中應用了動畫視圖修飾符。在 ViewBuilder 閉包內部,可以安全地對視圖應用任何視圖修飾符,并期望僅對此代碼塊進行動畫處理。
struct ContentView: View {@State private var firstStep = false@State private var secondStep = falsevar body: some View {VStack {Button("Animate") {Task {firstStep.toggle()try? await Task.sleep(nanoseconds: 1_000_000_000)secondStep.toggle()}}// 其他視圖在這里SomeView().transaction { t int.animation = t.animation?.speed(2)} body: { content incontent.opacity(firstStep ? 1.0 : 0.0).blur(radius: secondStep ? 0 : 20.0)}}}
}
正如你所看到的,SwiftUI 提供了一種類似的方法,以在視圖層次結構中維護有作用域的事務。
總結
這篇文章介紹了在SwiftUI中構建動畫的新方法,重點解決了在多步動畫或特定視圖層次結構中控制動畫的挑戰。通過引入帶有value
參數的動畫修飾符,以及使用ViewBuilder
閉包限定動畫范圍,作者展示了更精確和靈活的動畫控制方式。
這種方法在處理多個可動畫屬性時尤其強大。文章還提到了SwiftUI引入的一項新變體,使用ViewBuilder
閉包可在動畫中應用視圖修飾符,有效地將動畫范圍限定在特定的上下文中。
最后,介紹了在 SwiftUI 中構建有作用域的事務的新方法,以維護更具精確性和可控性的動畫。這些新功能在最新的平臺上可用,為SwiftUI開發者提供了更強大的動畫工具。