動畫分析步驟“三步曲”

摘要: 本文將實現簡單的“登錄界面按鈕移動效果”,並通過此動畫效果介紹動畫設計和分析的思路。本文不僅旨在讓大家弄清動畫效果是如何通過代碼來實現的,更重要的是希望大家通過對本文的學習,掌握動畫設計和分析的思路。本文選自《iOS動畫——核心技術與案例實戰》

  首先先來看看動畫設計中的三個角色:產品設計師、算法分析師以及偉大的程序員都有哪些職責。
(1)產品設計師:告訴大家想做一個什麼樣的動畫。
(2)算法分析師:分析動畫的實現原理並設計相應的動畫算法。
(3)程序員:思考如何用代碼實現算法。
  在一般中小規模的公司中,開發人員往往都是身兼數職。不僅要編寫代碼還要參與到算法的設計中去,甚至參與到動畫原型的設計中去。所以弄清楚動畫設計過程中的不同角色,以及搞清楚動畫的分析過程是非常有必要的。

1 動畫分析方法

  下圖是我們想要實現的動畫效果,那麼如何來分析它呢?其實產品設計師在設計動畫時,如果能夠將動畫分解爲單幀圖像,或者能夠較爲慢速地展現動畫的變化過程,那麼對於算法分析師和程序員分析動畫的原理,以及設計合適的展現算法起着非常重要的作用。下圖描述了登錄按鈕從左到右逐漸移動的效果,並最後停留在視圖層中間位置這一過程。
【圖1】

  這個動畫效果非常簡單,可以用一句話來描述其實現算法,即圖像的水平方向位置座標和時間呈線性漸變關係。接下來思考如何用代碼實現這個效果。按照動畫的展示過程,這裏將動畫分爲:動畫起始階段、動畫進行階段和動畫結束階段。

1.動畫起始階段

  在動畫啓動的瞬間,希望動畫從屏幕可視界面外飛入進來。如下圖所示的登錄按鈕是需要實現的動畫起始位置。
【圖2】
  在iOS視圖中,左上角爲視圖的原點(0,0),水平向右爲x軸遞增方向,豎直向下爲y軸遞增方向,只有當View視圖位於手機屏幕展示座標系之內,大家才能看到(虛線區域內控件不可見),否則登錄按鈕是不可見的。所以在動畫的起始階段可以將動畫的位置屬性設置在界面之外。

2.動畫進行階段

  經過前面的分析,大家已經瞭解了這個動畫效果的實現算法,即登錄按鈕的座標沿水平方向隨時間線性變化。如表1.1所示描述了不同時間段登錄按鈕的座標變化情況。幸運的是大家不需要手動設計這一過程,甚至不需要手動寫線性漸變的方法,因爲iOS在UIView的顯示層已經幫我們把這個功能集成了。iOS在UIView圖層中不僅集成了動畫的線性漸變方法,而且動畫的加速、減速以及複雜的動畫變化時間函數、運動路徑函數也已經爲大家集成好了,所以只需要學會如何使用這些豐富的API即可,且這個功能只需要幾行代碼就可以實現。
  表1.1 6S下QQ圖標移動效果:QQ圖標x、y座標隨時間變化關係表
圖片描述

3.動畫結束階段

  在動畫效果結束之後沒有觸發新的回調事件,只是更新了當前登錄按鈕的最後位置,所以圖片最終停留在視圖層的中間位置。

2 登錄按鈕移動動畫效果:閉包形式

首先創建一個單視圖工程,創建好之後可以看到下圖的工程文件目錄結構:
【圖3】
  動畫實現的第一階段:動畫起始階段
  在開始正式添加動畫代碼之前需要爲應用添加一個背景圖片。在Main.storyboard中爲整個工程添加一個已經準備好的背景圖片,背景圖片依託在UIImageView上。
【圖4】
  上圖爲當前工程的Main.storyboard中圖層結構,其中View Controller爲整個工程的視圖控制器,login爲UIImageView登錄背景圖片。下圖示是準備好的背景圖片,通過下圖可以看出,要想實現最初所示的動畫效果,只需爲整個登錄界面添加一個登錄按鈕即可。
【圖5】
  動畫起始階段代碼需要放在什麼位置才合適呢?要想弄清楚這個問題先搞清楚ViewController.swift 中幾個方法的執行順序。需要關注以下3個方法。

viewDidLoad()
viewWillAppear()
viewDidAppear()

  在應用啓動之後,在viewDidLoad中會裝載所有的View視圖,注意,雖然所有View視圖都被裝載進來,但是這時所有的View視圖並不是可見的。程序接着調用viewWillAppear方法,這是視圖在展現之前需要調用的方法。而最後調用viewDidAppear,表明所有的視圖已經可見。經過以上分析,大家應該清楚,在動畫起始階段可以將所有的初始化代碼放置在viewDidLoad()方法中。具體實現代碼如下所示。

1   var loginButton:UIButton?
2   override func viewDidLoad() {
3       super.viewDidLoad()
4       loginButton = UIButton(frame: CGRect(x:-394,y:230,
                      width:self.view.frame.width-20*2,height:50))
5      loginButton!.backgroundColor = UIColor(red: 50/255.0, green: 185/255.0, blue: 170/255.0, alpha: 1.0)
6       loginButton!.setTitle("登錄", for: UIControlState. normal)
7      self.view.addSubview(loginButton!)
    }

  代碼第1行創建了一個UIButton登錄按鈕。第3行重寫viewDidLoad方法,表明應用啓動之後首先通過調用viewDidload方法加載各種UI組鍵。第4行設置當前UIButton登錄按鈕的位置,按鈕的x座標設置在整個界面之外,因此當前Button按鈕是不可見的。第5行爲登錄按鈕添加一個淡綠色背景。第6行設置登錄按鈕Title內容。最後一行將按鈕添加到self.view圖層上。
  動畫實現的第二階段和第三階段:動畫進行階段和動畫結束階段
要想實現應用打開動畫即展現的效果,需要在View視圖整體展現之前完成動畫實現的第二階段和第三階段的設置(因爲如果視圖已經顯示了才設置動畫效果,那麼會有動畫不連貫的現象),所以這部分功能只能放置在viewWillAppear方法中。
這裏使用的UIButton按鈕和UI控件都是繼承UIView類,UIView類中有一個動畫方法可以完成我們想要實現的功能:

open class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Swift.Void)

  該方法屬於類方法,類名可以直接調用,表明爲當前的UIView添加一個動畫效果,它的每個參數的含義如下。

  • duration:表明動畫執行週期。
  • animations:表明動畫執行內容。

注意,這裏animations是一個閉包,使用閉包的方式將動畫代碼追加進去。在閉包中只需要將動畫的結束狀態設置完成,那麼動畫從開始到結束的中間過程,iOS都會自動實現。下面爲viewWillAppear()中的動畫實現代碼。

    override func viewWillAppear(_ animated: Bool) {
        UIView.animate(withDuration: 1, animations: {
          self.loginButton!.frame = CGRect(x:20,
                y:self.loginButton!.frame.origin.y, 
                 width:self.loginButton!.frame.width, 
                 height:self.loginButton!.frame.height))
        })
    }

  animate方法中,duration表明動畫執行週期爲1s,動畫閉包部分表明登錄按鈕最終的位置,即最終停留在手機屏幕的中間位置。

3 登錄按鈕移動動畫效果:方法形式

  除了使用閉包的方法之外,還可以使用另外一種方式實現這個動畫效果,即通過commit相關方法的形式來實現。通過修改viewWillAppear()中的內容,可以實現相同的動畫效果。下面是動畫移動效果的另外一種代碼實現方式。

    override func viewWillAppear(animated: Bool) {
1        UIView.beginAnimations(nil, context: nil)//動畫開始
2        UIView.setAnimationDuration(1)//動畫週期設置
3        loginButton!.frame = CGRect(x:20,
               y:loginButton!.frame.origin.y,
               width:loginButton!.frame.width,
               height:loginButton!.frame.height)//動畫位置設置
4       UIView.commitAnimations()//動畫提交
    }

  代碼第1行表明動畫開始,這裏先忽略需要傳遞的參數,可以先傳遞兩個nil。第2行設置動畫執行週期,這裏將動畫週期設置爲1s。第3行將登錄按鈕設置在屏幕中間位置。代碼最後一行將動畫效果提交到系統上運行。
  其實無論是第2節的動畫實現方法抑或是第3節的動畫實現方法,都可以把動畫實現的過程總結爲下面的3個步驟。
【圖6】
  而第2節和第3節實現動畫的唯一區別就是一個使用閉包的形式,而另一個使用beginAnimations和commitAnimations方法的形式啓動動畫。

4 UIView視圖中常見動畫的屬性分析

  我們在第2節和第3節主要依靠UIView下的frame屬性來實現登錄按鈕從左到右的進入效果。那麼UIView下的其他屬性是不是也可以有類似的效果呢?要想回答這個問題,首先需要弄清楚UIView都有哪些常見的屬性。

1.位置屬性:frame bounds center

  frame、bounds、center都是描述UIView的位置信息,不同的是frame可以對x座標、y座標、width、height四個屬性進行操作,frame的x座標和y座標相對於父控件的原點來計算,而bounds一般只能對width、height進行操作,它的x、y座標只相對於自身而言,center描述的是x、y信息,即UIView的中心位置。下面是CGRect、origin、size的代碼描述。

public struct CGRect {
    public var origin: CGPoint
    public var size: CGSize
    public init()
    public init(origin: CGPoint, size: CGSize)
}

  再來看看三者的數據類型。frame是CGRect類型,它是一個結構體,在結構體中包含origin和size兩個屬性。其中origin描述UIView的x、y座標起始位置信息,size描述UIView的width、height寬高信息。我們再來看看origin的CGPoint和size的CGSize又是什麼。

  CGpoint中包含了UIView的x、y座標,而CGSize中包含了UIView的Width、Height信息。通過對frame中數據類型的追本溯源,可以得到以下結論:CGRect分別對應x座標、y座標、width、height四個屬性。這四個屬性表明當前UI在它的父控件上的位置,如self.view上。
  通過以上分析可以知道,可以通過x、y座標修改UIView的移動位置,還可以通過修改width或者height來修改UIView的拉伸、收縮效果。對於bounds屬性使用最多的還是width、height屬性,center則經常使用x、y座標屬性。

2.透明度屬性:alpha(透明度屬性、範圍0-1、浮點型)

  UIView的alpha透明度屬性也可以用作動畫效果。當alpha爲0時,表明UIView已經隱藏,當alpha爲1時UIView顯示。結合這一特徵可以通過修改alpha在動畫開始、結束時的值,實現UIView的淡入淡出效果。

3.Layer屬性:圓角漸變、邊框顏色、陰影、3D等高級動畫效果

  UIView是視圖顯示的容器,負責內容顯示和事件響應。每個UIView都有一個Layer圖層,在這個圖層中承載的是視圖的內容,所以結合Layer可以實現很多高級的動畫效果。當然除了這些之外,UIView還有很多其他屬性,在後面的章節中會爲大家一一呈現。

5 小結

  通過對本文的學習,相信大家基本上掌握了動畫分析的基本步驟,在這裏總結一下動畫實現的三個步驟:
(1)設置視圖的動畫初始狀態。
(2)添加視圖的動畫相應屬性。
(3)設置視圖的動畫最終狀態。
  在通過幀分解等方法瞭解了動畫的實現原理之後,通過這三個步驟可以很方便地實現各種動畫效果。本章結合登錄按鈕移動效果爲大家展示了動畫分析和實現的全過程,並通過代碼詳細介紹了通過閉包方式,以及beginAnimations和commitAnimations方法的形式實現動畫。
  對於UIView中常見的動畫屬性,結合UIView對視圖的位置、透明度、幾何形狀給大家做了簡要的分析,在後面的章節中會結合具體的代碼,爲大家呈現繽紛多彩的動畫效果。
  本文選自《iOS動畫——核心技術與案例實戰》,點此鏈接可在博文視點官網查看。
                      圖片描述
  想及時獲得更多精彩文章,可在微信中搜索“博文視點”或者掃描下方二維碼並關注。
                       圖片描述

發佈了187 篇原創文章 · 獲贊 0 · 訪問量 8380
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章