動畫實作

輕鬆實作 Table View 動畫效果 為 App 大幅提升用戶體驗!

輕鬆實作 Table View 動畫效果 為 App 大幅提升用戶體驗!
輕鬆實作 Table View 動畫效果 為 App 大幅提升用戶體驗!
In: 動畫實作
本篇原文(標題:Animating Table View Cells Display)刊登於作者部落格,由 Vadim Bulavin 所著,並授權翻譯及轉載。

本文將會教你如何為 Table View Cell 添加自定義顯示動畫,提升 App 的用戶體驗 (User Experience)。

問題敘述

動畫效果是提升用戶體驗的關鍵因素。我猜你在當前專案中至少使用一個 Table View,考慮到 Table View 在 iOS App 中被廣泛運用,開發引人注目的加載動畫,將可顯著提升 App 的用戶體驗。

那麼,讓我們看看幾行程式碼如何能為你的 App 帶來新價值吧!

開始實作

首先,下載初始專案,這樣就可以節省編寫樣板程式碼和初始設置的時間。運行後,你會看到帶有靜態 Cell 的 UITableView

animation starter

打開 TableViewController.swift 後,你就會看到需要加工的初始代碼:

@IBAction func onRefresh(_ sender: UIBarButtonItem) {
    // Refresh table view here
}

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // Add animations here
}

onRefresh 函式負責處理右側 navigation bar 按鈕的點擊動作,稍後我們將添加觸發動畫的程式碼,但現在先保持原樣。

所有操作都將在 tableView(_:willDisplay:,forRowAt:) 中進行。讓我們添加一些簡單的動畫,來看看它能否正常運行。

實作簡單動畫

讓我們從一個簡單的淡入淡出動畫 (Fade Animation) 開始。UIView一系列的方法可以自己製作動畫視圖。

將這段程式碼添加至 tableView(_:willDisplay:,forRowAt:)

cell.alpha = 0

UIView.animate(
    withDuration: 0.5,
    delay: 0.05 * Double(indexPath.row),
    animations: {
        cell.alpha = 1
})

運行專案來查看動畫的實際成果。

simple animation

實作更複雜的動畫

在實作動畫效果時,很難只透過程式碼來判斷其好壞程度,通常你都要反覆嘗試多個變數,才會得到滿意的方案。優秀的開發人員會希望遵循最佳實踐 (best practice) 來製作一個可重用的方案,以便輕鬆插入和調整動畫。本節將著重在發展這樣的基礎。

我們要做的第一件事是定義 Animation 型別,它本質上是一個接受多個參數的閉包:

typealias Animation = (UITableViewCell, IndexPath, UITableView) -> Void

Animator 適合運行動畫,還確保動畫不會對所有可見 cell 運行多於一次。

嘗試 Animator 類別並移除 hasAnimatedAllCells 屬性,看看滑動 (scroll) 行為有何變化。

final class Animator {
    private var hasAnimatedAllCells = false
    private let animation: Animation

    init(animation: @escaping Animation) {
        self.animation = animation
    }

    func animate(cell: UITableViewCell, at indexPath: IndexPath, in tableView: UITableView) {
        guard !hasAnimatedAllCells else {
            return
        }

        animation(cell, indexPath, tableView)

        hasAnimatedAllCells = tableView.isLastVisibleCell(at: indexPath)
    }
}

現在,我們希望動畫越靈活越好,以便輕鬆地調整和替換它們。為此,我們來實作會自己創建動畫 AnimationFactory,這個工廠已經添加了我們淡入淡出的動畫:

enum AnimationFactory {

    static func makeFadeAnimation(duration: TimeInterval, delayFactor: Double) -> Animation {
        return { cell, indexPath, _ in
            cell.alpha = 0

            UIView.animate(
                withDuration: duration,
                delay: delayFactor * Double(indexPath.row),
                animations: {
                    cell.alpha = 1
            })
        }
    }
}

以下列程式碼取代 TableViewController.swift 中的舊動畫程式碼:

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let animation = AnimationFactory.makeFadeAnimation(duration: 0.5, delayFactor: 0.05)
    let animator = Animator(animation: animation)
    animator.animate(cell: cell, at: indexPath, in: tableView)
}

現在我們只需要添加刷新功能就可以了!

@IBAction func onRefresh(_ sender: UIBarButtonItem) {
    tableView.reloadData()
}

讓我們運行專案,看看它是否按預期運作。

在這裡,我們順利重構了之前不可重用的動畫程式碼,並用新而漂亮的動畫程式碼取而代之。現在我們已經準備好實作更酷的東西了!

彈跳動畫 (Bounce Animation)

要實現更複雜的動畫,你需要利用 UITableViewCelltransform 屬性,以將 2D 變換例如旋轉、縮放、移動或傾斜等效果應用於 cell。這就是我們要為彈跳動畫所做的事情。

UIKit 功能強大,可讓你通過單一方法定義彈跳動畫。請記住,我們將所有新動畫程式碼放入了工廠類別中。打開 AnimationFactory.swift 並添加下一個方法:

static func makeMoveUpWithBounce(rowHeight: CGFloat, duration: TimeInterval, delayFactor: Double) -> Animation {
    return { cell, indexPath, tableView in
        cell.transform = CGAffineTransform(translationX: 0, y: rowHeight)

        UIView.animate(
            withDuration: duration,
            delay: delayFactor * Double(indexPath.row),
            usingSpringWithDamping: 0.4,
            initialSpringVelocity: 0.1,
            options: [.curveEaseInOut],
            animations: {
                cell.transform = CGAffineTransform(translationX: 0, y: 0)
        })
    }
}

讓我解釋幾個重點:

  • dampingRatio ── 基本上是一種彈跳力量,數值為 1 表示根本沒有彈跳效果,數值越接近 0 表示彈跳效果越強。
  • velocity ── 彈跳速度。數值為 1 代表一秒內行進的總動畫距離。
  • options ── 動畫視圖的 options,我們使用 .curveEaseInOut 來使動畫慢慢開始,在其持續時間中間加速,然後在完成之前再次減速。

要找到傳遞給動畫函式最適合的數值,就要不斷調整動畫來嘗試。

小提示:嘗試傳遞不同的 options 數值,以查看 options 如何影響 cell 的動畫。

更新 TableViewController 中的程式碼,以新的彈跳動畫取代淡入淡出動畫。

let animation = AnimationFactory.makeMoveUpWithBounce(rowHeight: cell.frame.height, duration: 1.0, delayFactor: 0.05)
let animator = Animator(animation: animation)
animator.animate(cell: cell, at: indexPath, in: tableView)

動畫會產生這樣的效果:

bounce animation

移動和淡化動畫 (Move and Fade Animation)

我們下一個實作的動畫會做兩件事:移動 Cell、並同時淡化它們。為此,我們使用 UITableViewCelltransformalpha 屬性。

static func makeMoveUpWithFade(rowHeight: CGFloat, duration: TimeInterval, delayFactor: Double) -> Animation {
    return { cell, indexPath, _ in
        cell.transform = CGAffineTransform(translationX: 0, y: rowHeight / 2)
        cell.alpha = 0

        UIView.animate(
            withDuration: duration,
            delay: delayFactor * Double(indexPath.row),
            options: [.curveEaseInOut],
            animations: {
                cell.transform = CGAffineTransform(translationX: 0, y: 0)
                cell.alpha = 1
        })
    }
}

像剛才一樣,將新動畫程式碼放在 TableViewController 中。

let animation = AnimationFactory.makeMoveUpWithFade(rowHeight: cell.frame.height, duration: 0.5, delayFactor: 0.05)
let animator = Animator(animation: animation)
animator.animate(cell: cell, at: indexPath, in: tableView)

運行 App,動畫應該像這樣:

move and fade animation

滑入動畫 (Slide in Animation)

我相信你已經掌握了編寫動畫的訣竅,並開始欣賞你在前文構建的可重用方案。

滑入動畫一如其名,就是將 Cell 從螢幕的右邊邊緣移動到 TableView 的實際位置。為此,我們還是會使用 transform 屬性。現在,我們將這個動畫程式碼添加到工廠。

static func makeSlideIn(duration: TimeInterval, delayFactor: Double) -> Animation {
    return { cell, indexPath, tableView in
        cell.transform = CGAffineTransform(translationX: tableView.bounds.width, y: 0)

        UIView.animate(
            withDuration: duration,
            delay: delayFactor * Double(indexPath.row),
            options: [.curveEaseInOut],
            animations: {
                cell.transform = CGAffineTransform(translationX: 0, y: 0)
        })
    }
}

接下來,更新 TableViewController 程式碼以使用滑入動畫。

let animation = AnimationFactory.makeSlideIn(duration: 0.5, delayFactor: 0.05)
let animator = Animator(animation: animation)
animator.animate(cell: cell, at: indexPath, in: tableView)

完成後,動畫應該像這樣:

slide in animation

專案原始碼

你可以在此處下載最終專案初始專案。如有任何問題,歡迎讀者在下面提出。

總結

動畫對每個 iOS App 的用戶體驗中都非常重要。TableView 是 iOS 中最廣泛使用的組件,因此開發炫麗的 Cell 動畫對你專案的用戶體驗十分有利。我們設計的可重用方案可以輕鬆插入和調整動畫,以便在你目前開發的 App 中進行調整和使用。

希望這個動畫實作方法能為你們提供一個良好的基礎,作為你在使用 Table View Cell 顯示動畫的良好開端。

本篇原文(標題:Animating Table View Cells Display)刊登於作者部落格,由 Vadim Bulavin 所著,並授權翻譯及轉載。
作者簡介: Vadim,來自烏克蘭的 iOS 團隊負責人,持有電腦科學理學學士和碩士學位,專注於密碼學和數學。本來從事 C ++ 的密碼學和密碼分析領域工作,從 iOS 4 起發現 iOS 的開發樂趣。對 TDD 和 Clean Architecture 充滿熱情,在習慣在每個專案中都應用最佳開發實踐。在部落格定期編寫文章。
Twitter: https://twitter.com/V8tr
LinkedIn: https://www.linkedin.com/in/vadim-bulavin/
譯者簡介:陳奕先-過去為平面財經記者,專跑產業新聞,2015 年起跨進軟體開發世界,希望在不同領域中培養新的視野,於新創學校 ALPHA Camp 畢業後,積極投入 iOS 程式開發,目前任職於國內電商公司。聯絡方式:電郵 [email protected]

FB : https://www.facebook.com/yishen.chen.54
Twitter : https://twitter.com/YeEeEsS

作者
AppCoda 編輯團隊
此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。
評論
更多來自 AppCoda 中文版
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。