SwiftUI框架詳細解析 (八) —— 基于SwiftUI的動畫的實現(xiàn)(一)

版本記錄

版本號 時間
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:緩入和緩出曲線結合了easyIneaseOut欣福。 這對于從一個穩(wěn)定點開始并在另一個平衡點處結束的動畫很有用责球。 這是大多數(shù)應用程序的最佳選擇。 這就是為什么這是.default使用的時序曲線的原因拓劝。
  • .timingCurve:這使您可以指定自定義時序曲線雏逾。 這很少需要,并且不在本教程的討論范圍之內郑临。

大多數(shù)情況下栖博,.default足以滿足您的需求。 如果您還需要其他一些功能厢洞,則基本的計時功能之一將為您提供一些額外的改進仇让。 通過將.default替換為其中的一種來進行嘗試典奉,以找出最適合您的選擇。

上圖顯示了每個時序曲線隨時間的速度丧叽。 但是動畫將如何實際顯示卫玖? 將每個曲線應用到月亮按鈕的scaleEffect時,這是隨著時間變化的外觀踊淳。

Linear
EaseIn
EaseOut
EaseInOut

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可以應用于所有這些屬性喉刘。

通過將其放置在ImagescaleEffect線之間瞧柔,添加以下旋轉效果:

.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)生較大的位移呀狼,從而使其彈跳得越來越遠裂允。

彈簧越硬,其作用就相反-彈簧越硬哥艇,它將移動得越遠绝编。 增大阻尼就像增大摩擦:它將減少行程并縮短彈跳時間。 初始速度設置動畫的速度:更大的速度將使視圖移動更多,并使其彈跳時間更長十饥。

spring(response:dampingFraction:) curves for various parameters

很難將物理原理映射到動畫的實際工作方式怎棱。這就是為什么每次都使用一個參數(shù)以獲得漂亮的動畫非常有用。

這也是為什么有spring(response:dampingFraction:blendDuration)的原因绷跑,它是編寫spring動畫的一種更容易理解的方式拳恋。在幕后,它仍然使用物理模型砸捏,但杠桿較少谬运。

阻尼(dampingFraction)阻尼控制視圖反彈的時間。零阻尼是一個無阻尼的系統(tǒng)垦藏,這意味著它將永遠反彈梆暖。大于1的阻尼阻尼值根本不會彈起。如果您使用彈簧掂骏,通常會選擇一個介于0到1之間的值轰驳。較大的值會降低速度。

響應(response)是完成一次振蕩的時間量弟灼。這將控制動畫的持續(xù)時間级解。這兩個值協(xié)同工作以調整視圖的距離和速度,并且經(jīng)常會反彈視圖田绑。如果更改response或組合多個彈簧勤哗,blendDuration將影響動畫。這是一種高級機動掩驱。

Response curves for various interpolating spring parameters

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將其視圖繞一圈移動。它通過GeometryEffecteffectValue(size :)方法實現(xiàn)砌梆。此方法返回一個ProjectionTransform默责,它是一個坐標變換贬循。在這種情況下,將使用平移CGAffineTransform創(chuàng)建平移桃序,該平移對應于圓上的一個點杖虾。

GeometryEffect的神奇之處在于它符合Animatable。這意味著它需要一個名為animatableData的屬性媒熊。在這種情況下奇适,它包裝了一個名為percentCGFloat屬性。動畫數(shù)據(jù)可以是符合VectorArithmetic的任何值芦鳍,這意味著可以在起始值和結束值之間進行插值嚷往。為此,您將選擇0%100%之間的動畫柠衅。

通過計算0到之間的相對值皮仁,可以將百分比應用于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ù)可以消除沖突幌衣。

最后归敬,在ZStackmakeSystem(_ :)末尾,應用以下修飾符:

.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設置為。 確保您也用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更改為掂林,而不是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和諸如projectionEffecttransformEffect片习,scaleEffectrotationEffect之類的效果捌肴,您可以在視圖更改屏幕上位置時更改其位置和形狀。

后記

本篇主要講述了基于SwiftUI的動畫的實現(xiàn)藕咏,感興趣的給個贊或者關注~~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末状知,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子侈离,更是在濱河造成了極大的恐慌试幽,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卦碾,死亡現(xiàn)場離奇詭異铺坞,居然都是意外死亡,警方通過查閱死者的電腦和手機洲胖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門济榨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绿映,你說我怎么就攤上這事擒滑「溃” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵丐一,是天一觀的道長藻糖。 經(jīng)常有香客問我,道長库车,這世上最難降的妖魔是什么巨柒? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮柠衍,結果婚禮上洋满,老公的妹妹穿的比我還像新娘。我一直安慰自己珍坊,他們只是感情好牺勾,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著阵漏,像睡著了一般驻民。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上袱饭,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天川无,我揣著相機與錄音,去河邊找鬼虑乖。 笑死懦趋,一個胖子當著我的面吹牛,可吹牛的內容都是我干的疹味。 我是一名探鬼主播仅叫,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼糙捺!你這毒婦竟也來了诫咱?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤洪灯,失蹤者是張志新(化名)和其女友劉穎坎缭,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體签钩,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡掏呼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铅檩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片憎夷。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖昧旨,靈堂內的尸體忽然破棺而出拾给,到底是詐尸還是另有隱情祥得,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布蒋得,位于F島的核電站级及,受9級特大地震影響,放射性物質發(fā)生泄漏窄锅。R本人自食惡果不足惜创千,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一缰雇、第九天 我趴在偏房一處隱蔽的房頂上張望入偷。 院中可真熱鬧,春花似錦械哟、人聲如沸疏之。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锋爪。三九已至,卻和暖如春爸业,著一層夾襖步出監(jiān)牢的瞬間其骄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工扯旷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拯爽,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓钧忽,卻偏偏與公主長得像毯炮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耸黑,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容