生活随笔
收集整理的這篇文章主要介紹了
SwiftUI之深入解析如何定制视图的动画和转场
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、前言
- 使用 SwiftUI 可以把視圖狀態的改變轉成動畫過程,SwiftUI 會處理所有復雜的動畫細節。
- 本文中,會給跟蹤用戶徒步的圖表視圖添加動畫,使用 animation(_: ) 修改器給一個視圖添加動畫效果非常容易。
- 可以下載文末的示例代碼并跟著本篇教程一步步實踐,或者查看本篇完成狀態時的工程代碼去學習,就可以輕松完成視圖的動畫添加和轉場動畫設定。
二、給每個視圖單獨添加動畫
- 在視圖上使用 animation(_: ) 修改器時,SwiftUI 會在視圖的任何可進行動畫的屬性發生改變時產生對應的動畫效果。視圖的顏色、不透明度、旋轉角度、大小及一些其它屬性都是可進行動畫的:
- 在 HikeView.swift 中,打開實時預覽,體驗一下圖表的打開和隱藏,此時的狀態改變時是沒有添加動畫效果的。在本文中,保持實時預覽一直打開,每一步修改的效果就可以實時的看到:
- 給顯示/隱藏切換的箭頭按鈕添加旋轉動畫,會發現現在按鈕點擊時的旋轉有一個動畫過渡的效果:
struct HikeView: View {var hike
: Hike@
State private var showDetail
= falsevar body
: some
View {VStack {HStack {HikeGraph(hike
: hike
, path
: \
.elevation
).frame(width
: 50, height
: 30).animation(nil)VStack(alignment
: .leading
) {Text(hike
.name
).font(.headline
)Text(hike
.distanceText
)}Spacer()Button(action
: {withAnimation
{self.showDetail
.toggle()}}) {Image(systemName
: "chevron.right.circle").imageScale(.large
).rotationEffect(.degrees(showDetail
? 90 : 0)).scaleEffect(showDetail
? 1.5 : 1).padding().animation(.easeInOut
)}}if showDetail
{HikeDetail(hike
: hike
)}}}
}struct HikeView_Previews: PreviewProvider {static var previews
: some
View {VStack {HikeView(hike
: hikeData
[0]).padding()Spacer()}}
}
- 當視圖從隱藏到展示時,讓切換按鈕變大 1.5 倍:
- 把動畫的類型從 easeInOut 改為 spring(),SwiftUI 包含一些預設或可自定義的動畫類型,像彈簧(spring)動畫和類型液體(fluid)動畫類型,可以調整動畫開始前的等待時長、動畫的速度也可以指定讓動畫循環重復的進行:
- 如果只想讓按鈕具有縮放動畫而不進行旋轉動畫,可以在 scaleEffect 添加 animation(nil) 來實現。可以在這里做一些實驗,如果把其它的一些動畫效果結合在一起,會怎么樣呢?
三、把視圖的狀態改態轉化成動畫效果
- 學會給單個視圖添加動畫的方法,現在可以學習怎么在視圖的狀態發生改變時添加動畫效果,當用戶點擊按鈕時會切換 showDetail 狀態的值,在視圖變化過程中添加動畫效果:
- 把 showDetail.toggle() 包裹在 withAnimation 函數調用塊中。showDetail 的改變影響了視圖 HikeDetail 和詳情切換按鈕,在顯示/隱藏詳情的過程中都有了過濾動畫效果:
- 放慢動畫速度,可以觀察 SwiftUI 動畫在被中斷下是怎么運作的,給 withAnimation 傳入一個時長4秒的基本動畫參數 .easeInOut(duration:4),可以指定動畫過程時長,給 withAnimation 傳入的動畫參數與 .animation(_😃 修改器可用參數一致:
- 在動畫過程進行中點擊按鈕切換視圖狀態,查看對應的動畫被中斷時的效果:
四、定制視圖轉場動畫
- 開始之前,先把動畫時長參數 (.easeInOut(duration: 4)) 相關的代碼去掉,讓動畫不再緩慢進行。
- 默值情況下,視圖離屏和入屏時的動畫效果是漸隱/漸現, 這個默認的轉場效果可以使用 transition(_: ) 修改器進行定制:
- 給 HikeView 視圖添加 transition(_: ) 修改器,并定制轉場參數為 .slide,轉場動畫為滑入/滑出:
- 可以把滑入/滑出這種轉場動畫封裝起來,方便其它視圖復用同樣的轉場效果:
extension AnyTransition {static var moveAndFade
: AnyTransition {AnyTransition.slide
}
}struct HikeView: View {var hike
: Hike@
State private var showDetail
= falsevar body
: some
View {VStack {HStack {HikeGraph(hike
: hike
, path
: \
.elevation
).frame(width
: 50, height
: 30).animation(nil)VStack(alignment
: .leading
) {Text(hike
.name
).font(.headline
)Text(hike
.distanceText
)}Spacer()Button(action
: {withAnimation() {self.showDetail
.toggle()}}) {Image(systemName
: "chevron.right.circle").imageScale(.large
).rotationEffect(.degrees(showDetail
? 90 : 0)).scaleEffect(showDetail
? 1.5 : 1).padding()}}if showDetail
{HikeDetail(hike
: hike
).transition(.moveAndFade
)}}}
}
- 在 moveAndFade 轉場效果的定義中使用 move(edge:),讓滑入/滑出從屏幕的同一邊進行:
- 使用 asymmetric(insertion:removal: ) 修改器來定制視圖顯示/消失時的轉場動畫效果:
五、組合復雜的動畫效果
- 點擊圖表下面的三個按鈕,會在三個不同的數據集間進行切換并展示。現在使用組合動畫,讓圖表在不同數據集間切換時的轉換動畫流暢自然:
- 把 showDetail 的默認值改為 true,并把 HikeView 的預覽模式視圖固定在畫布上。這樣可以在編輯其它文件時,依然看到動畫效果的變化:
- 在 HikeGraph.swift 中定義了一個新的波動動畫,并把它與滑入/滑出動畫一起應用到圖表視圖上:
func magnitude(of range
: Range<Double>) -> Double {return range
.upperBound
- range
.lowerBound
}extension Animation {static func ripple() -> Animation {Animation.default}
}struct HikeGraph: View {var hike
: Hikevar path
: KeyPath<Hike.Observation, Range<Double>>var color
: Color {switch path
{case \
.elevation
:return .gray
case \
.heartRate
:return Color(hue
: 0, saturation
: 0.5, brightness
: 0.7)case \
.pace
:return Color(hue
: 0.7, saturation
: 0.4, brightness
: 0.7)default:return .black
}}var body
: some
View {let data
= hike
.observations
let overallRange
= rangeOfRanges(data
.lazy.map { $
0[keyPath
: self.path
] })let maxMagnitude
= data
.map { magnitude(of
: $
0[keyPath
: path
]) }.max()!let heightRatio
= (1 - CGFloat(maxMagnitude
/ magnitude(of
: overallRange
))) / 2return GeometryReader { proxy
inHStack(alignment
: .bottom
, spacing
: proxy
.size
.width
/ 120) {ForEach(data
.indices) { index
inGraphCapsule(index
: index
,height
: proxy
.size
.height
,range
: data
[index
][keyPath
: self.path
],overallRange
: overallRange
).colorMultiply(self.color
).transition(.slide
).animation(.ripple())}.offset(x
: 0, y
: proxy
.size
.height
* heightRatio
)}}}
}
- 把動畫切換為彈簧動畫(spring),并設置彈簧阻尼系數為 0.5,動畫過程中產生了逐漸回彈效果:
- 以當條形在圖表中的位置為參數,添加延遲效果,圖表中的每個條形會順序動起來:
- 觀察一下自定義波動(rippling)效果是怎么作用在視圖轉場中的。
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的SwiftUI之深入解析如何定制视图的动画和转场的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。