版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.12.11 星期三 |
前言
今天翻閱蘋果的API文檔框往,發(fā)現(xiàn)多了一個框架SwiftUI祸憋,這里我們就一起來看一下這個框架虐急。感興趣的看下面幾篇文章比庄。
1. SwiftUI框架詳細解析 (一) —— 基本概覽(一)
2. SwiftUI框架詳細解析 (二) —— 基于SwiftUI的閃屏頁的創(chuàng)建(一)
3. SwiftUI框架詳細解析 (三) —— 基于SwiftUI的閃屏頁的創(chuàng)建(二)
4. SwiftUI框架詳細解析 (四) —— 使用SwiftUI進行蘋果登錄(一)
5. SwiftUI框架詳細解析 (五) —— 使用SwiftUI進行蘋果登錄(二)
6. SwiftUI框架詳細解析 (六) —— 基于SwiftUI的導航的實現(xiàn)(一)
7. SwiftUI框架詳細解析 (七) —— 基于SwiftUI的導航的實現(xiàn)(二)
開始
首先看下主要內容
主要內容:在本教程中唉工,您將學習如何使用SwiftUI添加精美的動畫研乒。 您將從基本
(basic)
動畫過渡到復雜的自定義spring
動畫。
接著看下寫作環(huán)境
Swift 5, iOS 13, Xcode 11
SwiftUI
帶來了大量的新功能淋硝,并且為Apple的所有平臺編寫UI代碼提供了更簡便的方法告嘲。作為額外的好處,它還具有一種新的狀態(tài)轉換動畫方法奖地。
如果您習慣使用UIView
動畫橄唬,則可能會發(fā)現(xiàn)它們更易于編寫和理解。如果您要使用SwiftUI
参歹,那么恭喜您仰楚!這將使您輕松使用它。
在本教程中,您將學習SwiftUI
動畫的基礎知識僧界,包括:
-
animation
修改器侨嘀。 -
withAnimation
,該函數(shù)可讓您對狀態(tài)更改進行動畫處理捂襟。 - 自定義動畫咬腕。
最好使用Xcode 11.2.1
或更高版本,該版本包含SwiftUI
代碼中已知動畫bug
的修復程序葬荷。如果您運行的是macOS Catalina
涨共,則時間會更短一些,因為Xcode會在Canvas
窗格中并排顯示代碼和實時預覽宠漩。
但是举反,如果您仍然有Mojave
,那也可以扒吁;您可以構建并運行以查看代碼更改如何影響應用程序火鼻。實際上,由于預覽窗口可能有問題雕崩,因此該技術在Catalina
上仍然很方便魁索。
打開已有項目。
應用MySolarSystem
是對太陽系中行星的簡單清單(假設您正在地球上閱讀)盼铁。 完成后蛾默,點按一下即可顯示每個行星,并列出該行星最大的衛(wèi)星捉貌。 從那里輕敲月球將為用戶提供有關行星的其他信息支鸡。
ContentView
代表應用程序的主屏幕。 它是一個由Planets
數(shù)組構成表格的列表趁窃。 列表中的每個元素都是一個帶有多個控件的HStack
:一個用于行星圖片的Image
牧挣,一個用于行星名稱的Text
,一個Spacer
和一個按鈕Button
(如果該行星上有衛(wèi)星)醒陆。 此按鈕的目的是顯示有關衛(wèi)星的信息瀑构。
在本教程的后面,您將把可選的MoonList
放入VStack
刨摩。 點擊月亮按鈕將顯示或隱藏它寺晌。 這將是您要添加并設置動畫的第一件事。
1. Preview Window
如果您在macOS Catalina
上運行澡刹,則可以在編輯器窗格中訪問Canvas
呻征。 如果看不到它,請選擇Editor ? Canvas
以啟用它罢浇。 更改代碼后陆赋,將顯示視圖和實時更新沐祷。
如果單擊Live Preview
按鈕(又稱播放圖標),它將使預覽具有交互性攒岛。 添加動畫和交互性后赖临,您就可以單擊按鈕并觀察狀態(tài)變化。
注意:在撰寫本文時灾锯,預覽窗口并非
100%
可靠兢榨。 如果預覽停止更新,請檢查Canvas
頂部是否顯示以下消息:Automatic preview updating paused
顺饮。 如果看到吵聪,只需單擊Resume
即可重建預覽。 另外领突,如果動畫似乎無法正常運行暖璧,請通過在模擬器或設備上運行該應用進行仔細檢查案怯。 實時應用是任何UI行為的真實來源君旦。
Basic Animations
要添加動畫,您需要做的第一件事就是制作動畫嘲碱。 因此金砍,首先,您將創(chuàng)建一個狀態(tài)更改麦锯,以觸發(fā)對UI的更新恕稠。
打開ContentView.swift
并將以下內容添加到makePlanetRow(planet :)
中的VStack
的末尾:
if self.toggleMoons(planet.name) {
MoonList(planet: planet)
}
這會檢查toggleMoons(_ :)
,以確定是否應該切換該星球的行扶欣。 如果打開了衛(wèi)星鹅巍,則MoonStack
視圖將出現(xiàn)在VStack
中。 此方法與state
屬性showMoon
綁定料祠。
接下來骆捧,通過設置showMoon
屬性完成操作。 在按鈕的操作回調中髓绽,添加以下代碼:
self.showMoon = self.toggleMoons(planet.name) ? nil : planet.name
如果用戶已經(jīng)按下按鈕敛苇,此代碼將清除showMoon
;如果用戶選擇其他行顺呕,則將其設置為新的行星枫攀。
生成并運行該應用程序。 輕觸帶有“moon disclosure”
圖標的行株茶,將顯示卡通地圖以及該行星最大的一些衛(wèi)星的列表来涨。 該按鈕的大小也加倍,以引起人們的注意启盛。 這樣扫夜,用戶便知道在何處點擊以關閉該行楞泼。
這使月亮列表視圖內外閃爍,這幾乎不是很棒的用戶體驗笤闯。 幸運的是堕阔,添加一些動畫很容易。
首先為按鈕尺寸創(chuàng)建平滑的動畫颗味。 在月球圖像Image
上的scaleEffect
修改器之后超陆,添加以下修改器:
.animation(.default)
這會將默認動畫添加到縮放效果。 現(xiàn)在浦马,如果您展開或折疊一行时呀,則按鈕將平滑地增大或縮小。 如果您發(fā)現(xiàn)月亮視圖的瞬時外觀和消失有一些問題晶默,請不要擔心谨娜。 您將在下面的Animating State Changes
部分中對此進行修復。
1. Animation Timing
animation(_ :)
修飾符采用Animation
參數(shù)磺陡。
您可以將多個選項用于動畫趴梢。 基本的是簡單的時序曲線,它們描述了動畫速度在持續(xù)時間內如何變化币他。 這些都修改了變化的屬性坞靶,在起始值和結束值之間平滑地插值。
您有以下選擇:
-
.linear
:隨著時間的推移蝴悉,它將屬性從開始值到結束值均勻過渡彰阴。 這是重復動畫的良好時序曲線,但看起來不像eased function
那樣自然拍冠。
-
.easeIn
:緩動動畫從慢速開始尿这,并隨著時間的推移加快速度。 這對于從靜止點開始并在屏幕外結束的動畫很有用庆杜。
-
.easeOut
:緩動的動畫開始快而結束慢射众。 這對于使物體達到穩(wěn)態(tài)或最終位置具有動畫效果是很有用的。
-
.easeInOut
:緩入和緩出曲線結合了easyIn
和easeOut
欣福。 這對于從一個穩(wěn)定點開始并在另一個平衡點處結束的動畫很有用责球。 這是大多數(shù)應用程序的最佳選擇。 這就是為什么這是.default
使用的時序曲線的原因拓劝。
-
.timingCurve
:這使您可以指定自定義時序曲線雏逾。 這很少需要,并且不在本教程的討論范圍之內郑临。
大多數(shù)情況下栖博,.default
足以滿足您的需求。 如果您還需要其他一些功能厢洞,則基本的計時功能之一將為您提供一些額外的改進仇让。 通過將.default
替換為其中的一種來進行嘗試典奉,以找出最適合您的選擇。
上圖顯示了每個時序曲線隨時間的速度丧叽。 但是動畫將如何實際顯示卫玖? 將每個曲線應用到月亮按鈕的scaleEffect
時,這是隨著時間變化的外觀踊淳。
2. Tinkering With Timing
如果您看不到細微的差異假瞬,可以通過花費更多時間來放慢動畫的播放速度。 將animation
修改器替換為:
.animation(.easeIn(duration: 5))
指定更長的持續(xù)時間將使時序曲線更明顯迂尝。
在模擬器中而不是SwiftUI
預覽窗口中構建和運行的一個優(yōu)點是脱茉,您可以啟用Debug ? Slow Animations
標志。 這將大大降低任何動畫的速度垄开,因此您可以更清楚地看到細微的差異琴许。 這樣,您無需添加額外的duration
參數(shù)溉躲。
除了時序曲線和持續(xù)時間外榜田,您還可以使用其他一些控制桿來控制動畫的時序。 首先签财,有速度串慰。
在ContentView
的頂部創(chuàng)建一個新屬性:
let moonAnimation = Animation.easeInOut.speed(0.1)
該常量僅存儲動畫偏塞,因此您以后可以在代碼中更輕松地使用它唱蒸。 它還為您提供了一個改變周圍事物的場所。
接下來灸叼,替換Image
修改器:
.animation(moonAnimation)
現(xiàn)在神汹,月亮的大小將非常緩慢地調整。 嘗試將速度更改為2
古今,動畫將變得非称ㄎ海活潑。
除了速度之外捉腥,您還可以添加延遲delay
氓拼。 將moonAnimation
更改為:
let moonAnimation = Animation.easeInOut.delay(1)
現(xiàn)在,動畫具有一秒鐘的延遲抵碟。 在月亮列表中點擊該行閃爍桃漾,然后稍后,該按鈕將更改大小拟逮。 一次為多個屬性或對象設置動畫時撬统,Delay
最為有用,這將在后面介紹敦迄。
最后恋追,您可以使用修飾符來重復動畫凭迹。 將動畫更改為:
let moonAnimation = Animation.easeInOut.repeatForever(autoreverses: true)
現(xiàn)在,該按鈕將永遠跳動苦囱。 您還可以使用repeatCount(autoreverses :)
重復動畫有限的次數(shù)嗅绸。
完成實驗后,將動畫設置回:
let moonAnimation = Animation.default
3. Simultaneous Animations
.animation
是一個修飾符撕彤,可像其他修飾符一樣疊加到SwiftUI
視圖上朽砰。 如果視圖具有多個變化的屬性,則單個Animation
可以應用于所有這些屬性喉刘。
通過將其放置在Image
和scaleEffect
線之間瞧柔,添加以下旋轉效果:
.rotationEffect(.degrees(self.toggleMoons(planet.name) ? -50 : 0))
這會使moon
按鈕略微旋轉,因此當出現(xiàn)“月亮”視圖時睦裳,新月形會橫向排列造锅。 由于將動畫添加到最后,這些動畫將一起動畫廉邑。
當然哥蔚,您可以為每個屬性指定單獨的動畫。 例如蛛蒙,在rotationEffect
修改器之后添加以下修改器:
.animation(.easeOut(duration: 1))
這為旋轉提供了一秒鐘的動畫糙箍,因此與縮放效果相比,您會注意到旋轉結束的時間稍晚一些牵祟。 接下來深夯,將moonAnimation
更改為:
let moonAnimation = Animation.default.delay(1)
這會將大小動畫延遲一秒,因此縮放在旋轉完成后開始诺苹。 試試看咕晋。
最后,可以通過為動畫指定nil
來選擇不為特定屬性更改設置動畫收奔。 將rotationEffect
動畫更改為:
.animation(nil)
并將moonAnimation
更改為:
let moonAnimation = Animation.default
現(xiàn)在掌呜,僅動畫大小。
Animating State Changes
您花了一段時間完善了“月亮”按鈕的動畫效果坪哄,但是會出現(xiàn)在所有圓圈中的大視野呢质蕉?
好了,您可以使用簡單的withAnimation
塊為任何block
轉換設置動畫翩肌。 將按鈕操作塊的內容替換為:
withAnimation {
self.showMoon = self.toggleMoons(planet.name) ? nil : planet.name
}
withAnimation
明確告訴SwiftUI
要設置動畫模暗。 在這種情況下,它將對showMoon
和具有依賴于該屬性的任何視圖的切換進行動畫處理摧阅。
如果您現(xiàn)在觀看動畫汰蓉,將會看到月亮視圖使用默認的出現(xiàn)動畫逐漸消失,并且列表行滑出以騰出空間棒卷。
您還可以向顯式動畫塊提供特定的動畫顾孽。 用以下內容替換withAnimation
:
withAnimation(.easeIn(duration: 2))
現(xiàn)在祝钢,它使用持續(xù)時間為兩秒的緩動動畫,而不是default
若厚。
如果您嘗試一下拦英,放慢的動畫可能看起來不正確。 有更好的方法可以對進出層次結構的視圖進行動畫處理测秸。
在繼續(xù)之前疤估,將withAnimation
更改為:
withAnimation(.easeInOut)
1. Transitions
Transitions
介紹了如何插入或刪除視圖。 要查看其工作原理霎冯,請將此修飾符添加到if self.toggleMoons(planet.name)
塊中的MoonList
中:
.transition(.slide)
現(xiàn)在铃拇,視圖將滑入而不是淡入。從前緣滑入(Slide)
動畫沈撞,然后從尾隨滑出慷荔。
Transitions
屬于AnyTransition
類型。 SwiftUI
帶有一些預制的過渡:
-
.slide
:您已經(jīng)在使用中看到了它-將視圖從側面滑入缠俺。 -
.opacity
:此過渡使視圖淡入和淡出显晶。 -
.scale
:通過放大或縮小視圖進行動畫處理。 -
.move
:類似于slide
壹士,但是可以指定邊緣。 -
.offset
:沿任意方向移動視圖躏救。
繼續(xù)嘗試這些過渡唯笙,以了解它們的工作方式。
2. Combining Transitions
您還可以結合過渡來組成自己的自定義效果落剪。 在ContentView.swift
的頂部睁本,添加以下擴展名:
extension AnyTransition {
static var customTransition: AnyTransition {
let transition = AnyTransition.move(edge: .top)
.combined(with: .scale(scale: 0.2, anchor: .topTrailing))
.combined(with: .opacity)
return transition
}
}
它結合了三個過渡:從頂部邊緣移動尿庐,從20%錨定到頂部的scale
以及不透明的淡入淡出效果忠怖。
要使用它,請將MoonList
實例的transition
行更改為:
.transition(.customTransition)
構建并運行您的項目抄瑟,然后嘗試打開月球列表凡泣。 組合的效果就像視圖從“月亮”按鈕突然進出一樣。
3. Asynchronous Transitions
如果需要皮假,還可以使入口過渡與出口過渡不同鞋拟。
在ContentView.swift
中,將customTransition
的定義替換為:
static var customTransition: AnyTransition {
let insertion = AnyTransition.move(edge: .top)
.combined(with: .scale(scale: 0.2, anchor: .topTrailing))
.combined(with: .opacity)
let removal = AnyTransition.move(edge: .top)
return .asymmetric(insertion: insertion, removal: removal)
}
這樣可以保持插入狀態(tài)惹资,但是現(xiàn)在贺纲,月亮視圖通過移動到頂部退出屏幕。
Springs
現(xiàn)在褪测,衛(wèi)星列表僅顯示衛(wèi)星以同心圓彼此堆疊猴誊。 如果它們間隔開潦刃,甚至可以動畫進去,看起來會更好懈叹。
在MoonView.swift
中乖杠,將以下修飾符添加到body
鏈的末尾:
.onAppear {
withAnimation {
self.angle = self.targetAngle
}
}
這將在代表月亮的橙色球上設置一個隨機角度。 然后澄成,月亮將從直線上的零度動畫到新位置胧洒。
該動畫效果還不錯,因此您需要再添加一點點爵士樂墨状。 Spring
動畫使您可以添加一些彈跳和跳動卫漫,以使視圖生動活潑。
在SolarSystem.swift
中肾砂,將此方法添加到SolarSystem
中:
func animation(index: Double) -> Animation {
return Animation.spring(dampingFraction: 0.5)
}
此輔助方法創(chuàng)建一個Spring
動畫汛兜。
然后,在makeSystem(_ :)
的最后一個ForEach
中通今,將以下修飾符附加到self.moon
行:
.animation(self.animation(index: Double(index)))
這會將動畫添加到每個月球圓圈粥谬。 現(xiàn)在不用擔心index
; 您將在下一部分中使用它辫塌。
下次加載視圖時漏策,隨著衛(wèi)星到達其最終位置,將會有一些反彈臼氨。
1. Using SwiftUI’s Pre-Built Spring Options
像SwiftUI
中的所有其他內容一樣掺喻,spring
有一些內置選項:
-
spring()
:默認的彈簧行為。 這是一個很好的起點储矩。 -
spring(response:dampingFraction:blendDuration)
:帶有更多選項以微調其行為的彈簧動畫感耙。 -
interpolatingSpring(mass:stiffness:damping:initialVelocity :)
:一種非常可定制的基于物理建模的彈簧持隧。
Spring
動畫使用彈簧的真實世界作為基礎即硼。 想象一下,如果可以的話屡拨,請在彈簧線圈的末端安裝一個重塊只酥。 如果該塊的質量較大,則釋放彈簧會導致其下落時產(chǎn)生較大的位移呀狼,從而使其彈跳得越來越遠裂允。
彈簧越硬,其作用就相反-彈簧越硬哥艇,它將移動得越遠绝编。 增大阻尼就像增大摩擦:它將減少行程并縮短彈跳時間。 初始速度設置動畫的速度:更大的速度將使視圖移動更多,并使其彈跳時間更長十饥。
很難將物理原理映射到動畫的實際工作方式怎棱。這就是為什么每次都使用一個參數(shù)以獲得漂亮的動畫非常有用。
這也是為什么有spring(response:dampingFraction:blendDuration)
的原因绷跑,它是編寫spring
動畫的一種更容易理解的方式拳恋。在幕后,它仍然使用物理模型砸捏,但杠桿較少谬运。
阻尼(dampingFraction)
阻尼控制視圖反彈的時間。零阻尼是一個無阻尼的系統(tǒng)垦藏,這意味著它將永遠反彈梆暖。大于1的阻尼阻尼值根本不會彈起。如果您使用彈簧掂骏,通常會選擇一個介于0到1之間的值轰驳。較大的值會降低速度。
響應(response)
是完成一次振蕩的時間量弟灼。這將控制動畫的持續(xù)時間级解。這兩個值協(xié)同工作以調整視圖的距離和速度,并且經(jīng)常會反彈視圖田绑。如果更改response
或組合多個彈簧勤哗,blendDuration
將影響動畫。這是一種高級機動掩驱。
2. Refining the Animation
現(xiàn)在您對彈簧的工作原理有了更好的了解芒划,請花點時間整理動畫。 為一堆相對獨立的視圖制作動畫時欧穴,一件好事是給它們一些稍有不同的時間民逼。 這有助于使動畫更生動。
在SolarSystem.swift
中涮帘,將animation(index :)
更改為以下內容:
func animation(index: Double) -> Animation {
return Animation
.spring(response: 0.55, dampingFraction: 0.45, blendDuration: 0)
.speed(2)
.delay(0.075 * index)
}
這給每個“月球”增加了滾動延遲拼苍,因此它們彼此之間在75
毫秒后開始下降,從而產(chǎn)生了一些奇特的效果焚辅。
Animatable
這看起來不錯映屋,但如果衛(wèi)星沿軌道移動而不是從頂部彈起,那將更加現(xiàn)實同蜻。 您可以通過使用自定義修飾符GeometryEffect
來實現(xiàn)。 幾何效果描述了一種修改視圖位置早处,形狀或大小的動畫湾蔓。
將以下結構體添加到SolarSystem.swift
:
struct OrbitEffect: GeometryEffect {
let initialAngle = CGFloat.random(in: 0 ..< 2 * .pi)
var percent: CGFloat = 0
let radius: CGFloat
var animatableData: CGFloat {
get { return percent }
set { percent = newValue }
}
func effectValue(size: CGSize) -> ProjectionTransform {
let angle = 2 * .pi * percent + initialAngle
let pt = CGPoint(
x: cos(angle) * radius,
y: sin(angle) * radius)
return ProjectionTransform(CGAffineTransform(translationX: pt.x, y: pt.y))
}
}
此OrbitEffect
將其視圖繞一圈移動。它通過GeometryEffect
的effectValue(size :)
方法實現(xiàn)砌梆。此方法返回一個ProjectionTransform
默责,它是一個坐標變換贬循。在這種情況下,將使用平移CGAffineTransform
創(chuàng)建平移桃序,該平移對應于圓上的一個點杖虾。
GeometryEffect
的神奇之處在于它符合Animatable
。這意味著它需要一個名為animatableData
的屬性媒熊。在這種情況下奇适,它包裝了一個名為percent
的CGFloat
屬性。動畫數(shù)據(jù)可以是符合VectorArithmetic
的任何值芦鳍,這意味著可以在起始值和結束值之間進行插值嚷往。為此,您將選擇0%
到100%
之間的動畫柠衅。
通過計算0到2π
之間的相對值皮仁,可以將百分比應用于effectValue
。還有一個隨機的initialAngle
菲宴。這樣贷祈,每個“月球”將從不同的位置開始;否則喝峦,將它們全部緊緊地鎖定似乎很奇怪付燥。
要應用此效果,您需要稍微更改SolarSystem
視圖愈犹。首先键科,向其添加一個新的state
屬性:
@State private var animationFlag = false
動畫是根據(jù)狀態(tài)變化而發(fā)生的。 由于存在視圖時軌道動畫將保持不變漩怎,因此此簡單的布爾值將充當動畫的觸發(fā)器勋颖。
接下來,添加此輔助方法:
func makeOrbitEffect(diameter: CGFloat) -> some GeometryEffect {
return OrbitEffect(
percent: self.animationFlag ? 1.0 : 0.0,
radius: diameter / 2.0)
}
這將創(chuàng)建一個OrbitEffect
勋锤,將其百分比從0
開始饭玲,并在切換標志后將其更改為1
。
要調用此方法叁执,請在單個月亮ForEach
中茄厘,將.animation
修飾符替換為以下內容:
.modifier(self.makeOrbitEffect(
diameter: planetSize + radiusIncrement * CGFloat(index)
))
.animation(Animation
.linear(duration: Double.random(in: 10 ... 100))
.repeatForever(autoreverses: false)
)
通過使用輔助方法,這會將OrbitEffect
應用于每個月圓谈宛。 它還應用了隨機時間重復的線性動畫次哈。 這樣,每個月球將以各自獨立的速度無限期繞軌道運行吆录。 這不是行星的逼真的視圖窑滞,但看起來很漂亮。
接下來,替換moon(planetSize:moonSize:radiusIncrement:index :)
的實現(xiàn)哀卫,如下所示:
func moon(planetSize: CGFloat,
moonSize: CGFloat,
radiusIncrement: CGFloat,
index: CGFloat) -> some View {
return Circle()
.fill(Color.orange)
.frame(width: moonSize, height: moonSize)
}
以前的輔助方法使用MoonView
巨坊,該方法用于將自身放置在正確的半徑處。 現(xiàn)在,OrbitEffect
處理此放置,因此更改輔助函數(shù)可以消除沖突幌衣。
最后归敬,在ZStack
的makeSystem(_ :)
末尾,應用以下修飾符:
.onAppear {
self.animationFlag.toggle()
}
這將觸發(fā)該標志,并在顯示視圖時開始播放動畫。
現(xiàn)在,再次構建并運行妈候。 現(xiàn)在,月球將以不同的速度繞地球旋轉挂滓。
1. An Alternate Look at Animatable Data
在上一步中苦银,您通過將百分比從0更改為1來使效果動畫起來。這是對任何事物進行動畫處理的良好通用策略赶站。 例如幔虏,您可以對進度條執(zhí)行相同操作,并使用GeometryEffect
在整個屏幕上擴展該條的寬度贝椿。
或者想括,您可以直接為角度設置動畫并保存一個步驟。
在OrbitEffect
中烙博,將percentage
重命名為angle
瑟蜈,現(xiàn)在將其從0設置為2π
。 確保您也用animatableData
定義的angle
n
替換了percentage
渣窜。
接下來铺根,將effectValue(size :)
中的計算更改為:
func effectValue(size: CGSize) -> ProjectionTransform {
let pt = CGPoint(
x: cos(angle + initialAngle) * radius,
y: sin(angle + initialAngle) * radius)
let translation = CGAffineTransform(translationX: pt.x, y: pt.y)
return ProjectionTransform(translation)
}
這將直接使用angle
屬性,而不是基于百分比來計算角度乔宿。
然后位迂,將makeOrbitEffect(diameter :)
更改為:
func makeOrbitEffect(diameter: CGFloat) -> some GeometryEffect {
return OrbitEffect(
angle: self.animationFlag ? 2 * .pi : 0,
radius: diameter / 2.0)
}
在此,當切換animationFlag
時详瑞,更改將從0更改為2π
掂林,而不是0。
現(xiàn)在就構建并運行坝橡,但是您不會注意到動畫上的差異泻帮。
當起點和終點是任意的時,例如將用戶設置的兩個位置之間的視圖或其他視圖設置為動畫時驳庭,使用值與百分比的動畫效果最佳刑顺。
Other Ways to Animate
迄今為止氯窍,當視圖由于狀態(tài)變化而變化時饲常,您所看到的動畫類型將隱式或顯式地發(fā)生蹲堂。 您還可以通過顯式控制視圖的屬性來為視圖設置動畫。 例如贝淤,您可以循環(huán)更改視圖的offset
柒竞,以將其從一個位置移動到另一個位置。
在月球列表中點擊一個月球名稱播聪,將顯示該行星的詳細信息屏幕朽基,其中包含可滾動的月球縮略圖列表。 現(xiàn)在离陶,這個列表很無聊稼虎。
您可以通過使用rotation3DEffect
為其提供類似于CoverFlow
的界面來為列表增添趣味。
在MoonFlow.swift
中招刨,將以下內容添加到body
中間的VStack
的末尾:
.rotation3DEffect(
.degrees(Double(moonGeometry
.frame(in: .global).midX - geometry.size.width / 2) / 3),
axis: (x: 0, y: 1, z: 0)
)
這將沿y
軸應用旋轉效果霎俩,具體取決于單個VStack
距整個視圖中心的距離。 當用戶滾動時沉眶,該堆棧的幾何形狀將不斷變化打却,從而導致旋轉效果更新。 這樣可以平滑地改變旋轉效果谎倔,從而制作出動畫柳击。
通過結合使用GeometryReader
和諸如projectionEffect
,transformEffect
片习,scaleEffect
或rotationEffect
之類的效果捌肴,您可以在視圖更改屏幕上位置時更改其位置和形狀。
后記
本篇主要講述了基于SwiftUI的動畫的實現(xiàn)藕咏,感興趣的給個贊或者關注~~~