譯自 Showing and hiding views with transitions
更多內容,歡迎關注公眾號 「Swift花園」
喜歡文章?不如來個 ??➕三連?關注專欄,關注我 ???
用過渡顯示和隱藏檢視
SwiftUI 一個最強大的特性是可以定製檢視的顯示和隱藏。之前你已經見過我們如何使用常規的 if 條件來實現條件化檢視,也就是我們可以根據條件變化在檢視體系中插入或者移除檢視。
過渡控制這些插入和移除如何發生。我們可以使用內建的過渡,以各種方式組合它們,甚至完全自定義過渡。
下面用一個帶按鈕和矩形塊的 VStack 來演示:
struct ContentView: View {
var body: some View {
VStack {
Button("Tap Me") {
// do nothing
}
Rectangle()
.fill(Color.red)
.frame(width: 200, height: 200)
}
}
}複製程式碼
我們可以讓矩形塊在某個條件滿足時才出現。首先,新增一個狀態:
@State private var isShowingRed = false複製程式碼
然後用狀態作為條件來顯示矩形塊:
if isShowingRed {
Rectangle()
.fill(Color.red)
.frame(width: 200, height: 200)
}複製程式碼
最後,在按鈕的 action 中觸發 isShowingRed 在 true 和 false 間轉換:
self.isShowingRed.toggle()複製程式碼
執行程式,你會看到點選按鈕會顯示或者隱藏一個紅色矩形塊。但沒有動畫,它只是突然地出現或者消失。
我們可以用 SwiftUI 的預設檢視過渡來包裝狀態變化過程,像這樣:
withAnimation {
self.isShowingRed.toggle()
}複製程式碼
通過這個小改變,應用現在可以漸顯或者漸隱矩形塊,同時將按鈕上移或者下移來調整空間。看起來還不錯,但我們可以利用 transition() modifier 做到更好。
舉個例子,我們可以讓矩形塊以縮放的方式來出場和離場,新增 transition() modifier 給矩形塊:
Rectangle()
.fill(Color.red)
.frame(width: 200, height: 200)
.transition(.scale)複製程式碼
現在點選按鈕,看起來更好了:矩形塊隨著按鈕給它騰地方的時候變大,再點選按鈕,矩形塊又以縮小的方式消失。
如果你想實驗的話,有許多別的過渡可以嘗試。其中一個很有用的過渡是 .asymmetric ,它可以讓我們用一個過渡配置檢視顯示,另一個過渡配置檢視隱藏。儘管嘗試一下,把矩形塊的退出過渡換成下面的:
.transition(.asymmetric(insertion: .scale, removal: .opacity))複製程式碼
譯自 Building custom transitions using ViewModifier
用 ViewModifier 構建自定義過渡
用 SwiftUI 建立一個全新的過渡,是可能的,實際上非常容易。自定義過渡允許我們用完全自定義的動畫來新增或者移除檢視。
這個功能是通過 .modifier 過渡來實現的,它可以接收任意檢視 modifier 。要點在於我們需要例項化這個 modifier ,也就是自行建立它們。
讓我們動手嘗試。寫一個 view modifier ,實現一個類似 Keynote 裡最簡單的 Pivot 動畫 —— 讓一個新的幻燈片以旋轉的方式從左上角進入畫面 。用 SwiftUI 的術語來說,就是建立一個 view modifier,讓我們的檢視旋轉著從某一個角進入螢幕,但不逃出它本該有的邊界。 SwiftUI 直接提供了這樣的 modifier :rotationEffect() ,這個 modifier 讓我們在 2D 空間中旋轉檢視,而 clipped() 可以阻止超出檢視區域的部分被繪製。
rotationEffect() 和 rotation3DEffect() 相似,除了它只圍繞 Z 軸旋轉。不過,它還提供了控制旋轉錨點的能力 —— 錨點就是檢視中作為旋轉中心固定的部分。對此,SwiftUI 提供了 UnitPoint 型別,用於設定錨點,即可以指定精確的 X,Y 座標,也可以用許多內建的選項 —— .topLeading,.bottomTrailing,.center 等等。
讓我們建立一個 CornerRotateModifier 結構體,把上面介紹的知識點都放進去演示。這個 modifier 用一個錨點來控制旋轉中心,並且可以設定旋轉角度:
struct CornerRotateModifier: ViewModifier {
let amount: Double
let anchor: UnitPoint
func body(content: Content) -> some View {
content.rotationEffect(.degrees(amount), anchor: anchor).clipped()
}
}複製程式碼
額外的 clipped() 表示當檢視旋轉時,超出它本來的矩形區域的部分不做繪製。
我們可以利用 .modifier 過渡直接嘗試,但那樣的方式不常用。更好的方式通過擴充套件 AnyTransition 來使用。下面的擴充套件實現以左上角為錨點,從 -90 度旋轉到 0 度的過渡。
extension AnyTransition {
static var pivot: AnyTransition {
.modifier(
active: CornerRotateModifier(amount: -90, anchor: .topLeading),
identity: CornerRotateModifier(amount: 0, anchor: .topLeading)
)
}
}複製程式碼
上面的程式碼就緒後,我們可以用下面的程式碼附加這個過渡到任意檢視上:
.transition(.pivot)複製程式碼
我的公眾號 這裡有Swift及計算機程式設計的相關文章,以及優秀國外文章翻譯,歡迎關注~