【譯】用UIKit和UIView在視圖上執行iOS動畫

翻譯地址

本文旨在成爲iOS動畫的入門讀物,目的是詳盡地介紹不一樣的實現方法。php

鑑於該主題的普遍性,咱們將在至關高的層次上簡潔地涵蓋每一個部分。這樣作的目的是經過一組選項來教育讀者將動畫添加到他/她的iOS應用程序中。ios

在咱們開始討論與IOS相關的主題以前,讓咱們先簡單地看一看動畫的速度。git

60 Fps動畫

一般,在視頻中,每一幀由圖像表示,幀速率決定在序列中翻轉的圖像數量。這被稱爲「幀每秒」或FPS。github

FPS肯定在一秒鐘內翻轉的靜止圖像的數量,這實際上意味着圖像/幀的數量越多,視頻中顯示的細節/信息就越多。這也適用於動畫。swift

FPS一般用於肯定動畫的質量。有一種流行的觀點認爲,任何好的動畫應該運行在60英尺或更高-任何低於60 fps將感到有點不對勁。數組

你想看看30 FPS和60 FPS之間的區別嗎?看看這個!xcode

你注意到區別了嗎?人的眼睛確定能感受到低fps的抖動。所以,確保您所建立的任何動畫都遵循運行在60 fps或更高的基本規則,這是一個很好的實踐。這讓它感受更現實,更有活力。緩存

在查看了FPS以後,如今讓咱們深刻研究不一樣的核心iOS框架,這些框架爲咱們提供了一種執行動畫的方法bash

核心框架

在本節中,咱們將討論能夠用於建立視圖動畫的IOSSDK中的框架。咱們將對它們進行快速的瀏覽,並以相關的示例說明它們的特性集。<框架

UIKIT/UIVIEW動畫

UIView是任何在iOS應用程序中顯示內容的視圖的基類。

UIKit是爲咱們提供UIView的框架,它已經爲咱們提供了一些基本的動畫功能,使得開發人員能夠經過更少的操做來實現更多的目標。

APIUIView.animate,由於經過提供基於塊的語法中的屬性值,任何視圖的屬性均可以很容易地被動畫化。

在UIKit動畫中,建議只修改UIVIew的可動畫屬性,不然動畫可能會致使視圖處於意外狀態。

動畫(附圖:動畫:完成)

此方法接受動畫持續時間,這是一組須要動畫化的視圖的可動畫屬性更改。完成塊在視圖執行動畫時提供回調。

幾乎任何類型的動畫,如移動,縮放,旋轉,褪色,等等,在一個視圖能夠實現這個單一的API。

如今,考慮您想要動畫一個按鈕大小的變化,或者您想要一個特定的視圖放大到屏幕。這就是咱們如何使用UIView.animateAPI:

let newButtonWidth: CGFloat = 60

UIView.animate(withDuration: 2.0) { //1
    self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2
    self.button.center = self.view.center //3
}
複製代碼

咱們在這裏作的是:

  1. 咱們稱之爲UIView.animate方法具備傳遞給它的持續時間值,該值表示在塊中描述的動畫應該運行多長時間。
  2. 咱們設置按鈕的新框架,它應該表示動畫的最終狀態。
  3. 咱們設置按鈕center它的超級視圖的中心,使它保持在屏幕的中心。

上面的動畫代碼塊應該觸發按鈕框架的動畫,而不是當前的框架:

Width = 0, Height = 0

最後一個框架:

Width = Height = newButtonWidth

下面是動畫的樣子:

animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion

此方法相似於動畫方法的擴展,您能夠在前面的API中執行全部能夠執行的操做,並將一些物理行爲添加到視圖動畫中。

例如,若是您想在上面所作的動畫中實現彈簧阻尼效果,那麼代碼以下所示:

let newButtonWidth: CGFloat = 60
UIView.animate(withDuration: 1.0, //1
    delay: 0.0, //2
    usingSpringWithDamping: 0.3, //3
    initialSpringVelocity: 1, //4
    options: UIView.AnimationOptions.curveEaseInOut, //5
    animations: ({ //6
        self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth)
        self.button.center = self.view.center
}), completion: nil)
複製代碼

下面是咱們使用的一組參數:

  1. duration 表示肯定代碼塊應運行多長時間的動畫持續時間。
  2. delay 表示咱們但願在動畫開始以前具備的初始延遲。
  3. SpringWithDamping 表示咱們但願視圖表現的彈性效果的值。數值必須在0到1之間。值越低,彈簧振盪越高。
  4. velocity 表示動畫應以何種速度啓動。
  5. options 要應用於視圖動畫的動畫曲線類型。
  6. 最後,咱們設置須要動畫的按鈕框架的代碼塊。它和之前的動畫同樣。

下面是用上面的動畫配置動畫的樣子:

UIViewProperty動畫

爲了更好的控制動畫,UIViewPropertyAnimator它爲咱們提供了暫停和恢復動畫的方法。您能夠有自定義的定時,並使您的動畫具備交互性和可中斷性。這在執行動畫時很是有用,這些動畫也能夠與用戶操做交互。

經典的「滑動解鎖」手勢和播放器視圖「解散/擴展動畫」(在音樂應用程序中)是交互式動畫和可中斷動畫的例子。您能夠開始用手指移動視圖,而後釋放它,視圖將回到原來的位置。或者,您能夠在動畫期間捕捉視圖並繼續用手指拖動視圖。

下面是一個簡單的示例,說明如何使用UIViewPropertyAnimator:

let newButtonWidth: CGFloat = 60
let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1
    self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth)
    self.button.center = self.view.center
}
animator.startAnimation() //2
複製代碼

咱們正在作的事情以下:

  1. 咱們稱之爲UIViewPropertyAPI經過傳遞持續時間和動畫曲線。
  2. 與上面的UIView.動畫API不一樣,除非您本身指定動畫,即徹底控制完整的動畫過程/流,不然動畫不會啓動。

如今,讓咱們假設你想要更多的控制動畫。例如,您但願設計和控制動畫中的每一個幀。還有另外一個APIanimateKeyframes。可是在咱們深刻研究它以前,讓咱們快速地看看一個框架是什麼,在一個動畫中。

什麼是Aframe?

視圖的框架更改/轉換集合(從開始狀態到最終狀態)定義爲animation動畫期間視圖的每一個位置都被稱爲frame.

動畫關鍵幀

這個API提供了一種設計動畫的方法,使您能夠定義具備不一樣時間和轉換的多個動畫。發佈這篇文章後,API簡單地將全部動畫集成到一個無縫體驗中。

假設咱們想以隨機的方式移動屏幕上的按鈕。讓咱們看看如何使用KeyFrame動畫API來作到這一點。

UIView.animateKeyframes(withDuration: 5, //1
  delay: 0, //2
  options: .calculationModeLinear, //3
  animations: { //4
    UIView.addKeyframe( //5
      withRelativeStartTime: 0.25, //6
      relativeDuration: 0.25) { //7
        self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8
    }

    UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) {
        self.button.center = CGPoint(x: self.view.bounds.width, y: start.y)
    }

    UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
        self.button.center = start
    }
})
複製代碼

詳細狀況以下:

  1. duration 經過傳遞動畫的持續時間來調用API。
  2. delay 動畫的初始延遲持續時間。
  3. options 要應用於視圖動畫的動畫曲線類型。
  4. animations 塊,該塊接受開發人員/用戶設計的全部關鍵幀動畫。
  5. addKeyFrame 調用API來設計每一個動畫。在咱們的例子中,咱們定義了按鈕的每個動做。咱們能夠有更多的這樣的動畫,咱們須要,添加到塊。
  6. relativeStartTime 定義動畫塊集合中動畫的啓動時間。
  7. relativeDuration 定義此特定動畫的整體持續時間。
  8. center 在咱們的示例中,咱們只需更改按鈕的中間屬性,將按鈕移動到屏幕周圍。

最後的動畫是這樣的:

共動畫

任何基於UIKit的動畫都是在內部轉換成核心動畫。所以,核心動畫框架充當任何UIKit動畫的支持層或骨幹。所以,全部UIKit動畫API都只是以一種易於消費或方便的方式封裝了核心動畫API的層。

UIKit動畫API不提供對視圖執行的動畫的太多控制,由於它們主要用於視圖的可動畫屬性。所以,在這種狀況下,若是您想要控制動畫的每個幀,最好直接使用底層的核心動畫API。或者,UIView動畫和核心動畫也能夠一塊兒使用。

UIView+核心動畫

讓咱們看看如何從新建立相同的按鈕更改動畫,同時使用UIView和Core動畫API指定時間曲線。

咱們能夠用CATransaction的定時功能,它容許您指定和控制動畫曲線。

讓咱們來看一個按鈕大小變化動畫的例子,它的角半徑使用CATransaction的定時功能和UIView動畫的組合:

let oldValue = button.frame.width/2
let newButtonWidth: CGFloat = 60

/* Do Animations */
CATransaction.begin() //1
CATransaction.setAnimationDuration(2.0) //2
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3

// View animations //4
UIView.animate(withDuration: 1.0) {
    self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth)
    self.button.center = self.view.center
}

// Layer animations
let cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5
cornerAnimation.fromValue = oldValue //6
cornerAnimation.toValue = newButtonWidth/2 //7

button.layer.cornerRadius = newButtonWidth/2 //8
button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9

CATransaction.commit() //10
複製代碼

詳細狀況以下:

  1. begin 表示動畫代碼塊的開始。
  2. duration 總體動畫持續時間。
  3. curve 表示須要應用於動畫的計時曲線。
  4. UIView.animate 咱們的第一個動畫改變框架的按鈕。
  5. CABasicAnimation 咱們建立CABasicAnimation引用cornerRadius按鈕做爲鍵盤,由於這是咱們想要的動畫。相似地,若是但願對關鍵幀動畫具備粒度級控制,則可使用CAKeyframeAnimation班級。
  6. fromValue 表示動畫的起始值,即cornerRadius從動畫必須從哪裏開始的按鈕的值。
  7. toValue 表示動畫的最終值,即最終值。cornerRadius動畫必須結束的按鈕的值。
  8. cornerRadius 咱們必須設置`cornerRadius屬性的屬性,以動畫的最終值,不然,按鈕的角半徑值將在動畫完成後自動恢復到其初始值。
  9. addAnimation 經過表示動畫須要執行的Keypath,咱們將包含整個動畫過程配置的動畫對象附加到該層。
  10. commit 表示動畫代碼塊的結束並開始動畫。

最後的動畫是這樣的:

這個博客是一個偉大的閱讀,以幫助建立更高級的動畫,由於它整齊地帶您經過大多數核心動畫框架API指導您經過每一步的道路。

UIKITDYNAMICS

UIKitDynamic是UIKit的物理引擎,它使您可以在UIKit控件中添加任何物理行爲,如碰撞、重力、推、扣等。

UIKitDynamic動畫

這是UIKitDynamicyFramework的管理類,它規範由任何給定UI控件觸發的全部動畫。

UIKitDynamicBehavior

它使您能夠將任何物理行爲添加到動畫師中,從而使其可以在附在其上的視圖上執行操做。

UIKitDynamic的各類行爲包括:

  • UIAttachmentBehavior
  • UICollisionBehavior
  • UIFieldBehavior
  • UIGravityBehavior
  • UIPushBehavior
  • UISnapBehavior

UIKitDynamic的體系結構相似於。請注意,項目1至5能夠替換爲單個視圖。

讓咱們把一些物理行爲應用到咱們的按鈕上。咱們將看到如何將重力應用到按鈕上,這樣它就能給咱們一種處理真實物體的感受。

var dynamicAnimator   : UIDynamicAnimator!
var gravityBehavior   : UIGravityBehavior!

dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1

gravityBehavior = UIGravityBehavior(items: [button]) //2
dynamicAnimator.addBehavior(gravityBehavior) //3
複製代碼

詳細狀況以下:

  1. UIKitDynamicAnimator 咱們建立了一個UIKitDynamicAnimator對象,它充當執行動畫的協調器。咱們還傳遞了做爲引用視圖的按鈕的SuperView。

  2. UIGravityBehavior 咱們建立了一個UIGravityBehavior對象,並將咱們的按鈕傳遞到注入此行爲的數組元素中。

  3. addBehavior 咱們給動畫師添加了重力物體。

    這將建立以下所示的動畫:

    注意按鈕是如何從屏幕的中心(它的原始位置)掉到底部和後面的。

    咱們應該告訴動畫師考慮屏幕底部是地面。這裏是UICollisionBehavior進入畫面。

    var dynamicAnimator   : UIDynamicAnimator!
    var gravityBehavior   : UIGravityBehavior!
    var collisionBehavior : UICollisionBehavior!
    
    dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1
    
    gravityBehavior = UIGravityBehavior(items: [button]) //2
    dynamicAnimator.addBehavior(gravityBehavior) //3
    
    collisionBehavior = UICollisionBehavior(items: [button]) //4
    collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5
    dynamicAnimator.addBehavior(collisionBehavior) //6
    複製代碼
  4. UICollisionBehavior 咱們建立了一個UICollisionBehavior對象並沿按鈕傳遞,以便將行爲添加到元素中。

  5. translatesReferenceBoundsIntoBoundary 啓用此屬性會告訴動畫師將引用視圖邊界做爲結束,在咱們的示例中,這是屏幕的底部。

  6. addBehavior 咱們在這裏給動畫師添加了碰撞行爲。

    如今,咱們的按鈕應該按在地面上,靜止不動,以下所示:

    挺不錯的,不是嗎?

如今,讓咱們嘗試添加一個彈跳效應,使咱們的對象感受更真實。爲此,咱們將使用UIDynamicItemBehavior班級。

```
var dynamicAnimator   : UIDynamicAnimator!
var gravityBehavior   : UIGravityBehavior!
var collisionBehavior : UICollisionBehavior!
var bouncingBehavior  : UIDynamicItemBehavior!

dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1

gravityBehavior = UIGravityBehavior(items: [button]) //2
dynamicAnimator.addBehavior(gravityBehavior) //3

collisionBehavior = UICollisionBehavior(items: [button]) //4
collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5
dynamicAnimator.addBehavior(collisionBehavior) //6

//Adding the bounce effect
bouncingBehavior = UIDynamicItemBehavior(items: [button]) //7
bouncingBehavior.elasticity = 0.75 //8
dynamicAnimator.addBehavior(bouncingBehavior) //9
```
複製代碼
  1. UIDynamicItemBehavior 咱們建立了一個UIDynamicItemBehavior對象並沿按鈕傳遞,以便將行爲添加到元素中。
  2. elasticity 數值必須在0-1之間,它表明彈性,即物體在地面上和地面上彈跳的次數。這就是魔術發生的地方--經過調整這個屬性,你能夠區分不一樣種類的物體,好比球、瓶子、硬物品等等。
  3. addBehavior 咱們在這裏給動畫師添加了碰撞行爲。

如今,咱們的按鈕在觸地時應該會反彈,以下所示:

這個回購是很是有用的,並顯示了全部的UIKitDynamicsActions在行動中。它還提供了用於處理每一種行爲的源代碼。在我看來,這應該是一系列在視圖上執行iOS動畫的方法。

在下一節中,咱們將簡要介紹幫助咱們測量動畫性能的工具。我也建議你看看優化Xcode構建的方法由於它將節省大量的開發時間。

性能調諧

在本節中,咱們將研究如何測量和調優iOS動畫的性能。做爲iOS開發人員,您可能已經使用Xcode工具(如內存泄漏和分配)來衡量整個應用程序的性能。一樣,也有一些工具能夠用來衡量動畫的表現。

Core Animation儀器

試試看Core Animation儀器和你應該可以看到你的應用屏幕提供的FPS。這是一個很好的方法來衡量任何動畫呈如今你的iOS應用程序的性能/速度。

繪圖

FPS在這個應用程序中被大大下降了,它顯示的內容很重,就像圖像中的陰影同樣。在這種狀況下,而不是直接將圖像分配給UIImageView的圖像屬性,嘗試使用CoreGraphicsAPI在上下文中分別繪製圖像。當在單獨的線程中而不是在主線程中執行圖像解壓縮邏輯時,這會過分地減小圖像顯示時間。

光柵化

Rasteralization是一個用於緩存複雜層信息的過程,以便這些視圖在呈現時不會被從新繪製。重繪視圖是FPS減小的主要緣由,所以,最好對將要重複使用的視圖應用柵格化。

包起來

最後,我還總結了用於iOS動畫的有用資源列表。當你在iOS動畫上工做時,你可能會發現這很方便。此外,您可能還會發現這套設計工具在深刻研究動畫以前,做爲一個(設計)步驟頗有幫助。

我但願我已經可以涵蓋儘量多的主題,圍繞iOS動畫。若是我在這篇文章中遺漏了什麼,請在下面的評論部分告訴我,我很樂意作這個補充!

相關文章
相關標籤/搜索