iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0

swift

畫面有了~功能也有了~
接下來我們做個小動畫
我們試著讓小雞在畫面中跳起來
整個APP 感覺就活起來了
關於動畫~swift也不少方法都可以跑動畫
這邊我們採用影格動畫來玩看看
讓我們來看一下語法

UIView.animateKeyframes(
            withDuration: 動畫執行秒數,
            delay: 延期秒數,
            options: [.動畫參數],
            animations: {
                在這裡設定動畫影格
            },
            completion: {
                完成後要做的事情
            }
        )

語法上看起來不難對吧~
那我們來想一下小雞要怎麼動吧~
我們來做個小雞左右跳動的效果好了
左右跳動需要變更到以下屬性

屬性名稱 說明
translationX 透過改變x座標值, 讓小雞呈現左右移動的效果
rotated 透過變更角度, 讓小雞有種往上跳起, 與往下降落的感覺
centerY 利用改變中心Y軸, 來實現上下跳動的感覺, 其實也可以用translationY, 這邊是為了示範而用centerY
scaledX 當小雞跳到最左與最右時, 翻轉小雞, 小雞維持往前的效果, 如果沒有翻轉會看到小雞倒車跑
只需要這幾個屬性~就可以讓小雞動起來摟
animateKeyframes 只要我們設定每個關鍵時間點的屬性
接下來他就會幫我們把中間的數值補起來摟
讓我們來規劃一下動畫時間軸
為了不要讓時間被寫死, 我們用佔時百分比顯示
時間(用百分比表示) 說明
----- --------
0% => 10% 小雞往左邊跳起
10% => 20% 小雞往左邊降下
20% => 30% 小雞往左邊跳起
30% => 40% 小雞轉身往右邊降下迴轉
40% => 50% 小雞往右邊跳起
50% => 60% 小雞往右邊降下跳回原點
60% => 70% 小雞往右邊跳起
70% => 80% 小雞往右邊降下迴轉
80% => 90% 小雞轉身往左邊跳起
90% => 100% 小雞往左邊落下回原點
目前用這樣的思維來讓小雞左右跳動吧
接著我們看看關鍵影格的語法
UIView.addKeyframe(
    withRelativeStartTime: 動畫開始百分比, 
    relativeDuration: 動畫播放時間百分比,
    animations: {
        要變更的動畫屬性
    }
)

好摟~那我們來建立個資料模型吧

struct KeyFrameOptionItem {
    let startTime: Double // 動畫開始時間
    let translationX: CGFloat // 左右位移
    let centerY: Double // 上下跳動
    let rotated: CGFloat // 上下角度
    let scaledX: CGFloat // 水平翻轉
    
    init(startTime: Double, translationX: CGFloat, centerY: Double, rotated: CGFloat, scaledX: CGFloat)  {
        let oneDegree = CGFloat.pi / 180 // 透過pi轉換rotated角度
        self.startTime = startTime
        self.translationX = translationX
        self.rotated = rotated * oneDegree
        self.centerY = centerY
        self.scaledX = scaledX
    }
}

資料模型完成後
讓我們把動畫的參數都建立出來吧

var keyFrameOptions: Array<KeyFrameOptionItem> = []

keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.0, translationX: -33.0, centerY: 328.0, rotated: 10, scaledX: 1.0))
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.1, translationX: -66.0, centerY:  348.0, rotated: -10, scaledX: 1.0))
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.2, translationX: -99.0, centerY:  348.0, rotated: 10, scaledX: 1.0))
// 以上向左邊跳到底後轉身往回走
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.3, translationX: -66.0, centerY:  348.0, rotated: -10, scaledX:  -1.0))
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.4, translationX: -33.0, centerY: 348.0, rotated: 10, scaledX:  -1.0))
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.5, translationX: 0.0,  centerY: 348.0, rotated: -10, scaledX: -1.0))
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.6, translationX: 40.0, centerY:  348.0, rotated: 10, scaledX:  -1.0))
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.7, translationX: 100.0, centerY:  348.0, rotated: -10, scaledX: -1.0))
//跳到最右邊後 轉身往原點走
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.8, translationX: 40.0, centerY:  348.0, rotated: 10, scaledX:  1.0))
keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.9, translationX: 0.0, centerY:  348.0, rotated: -10, scaledX: 1.0))

接下來就設定repeat屬性與用for迴圈設定影格吧

UIView.animateKeyframes(
            withDuration: 4,
            delay: 0.0,
            options: [.repeat],
            animations: {
                for option in keyFrameOptions {
                    UIView.addKeyframe(
                        withRelativeStartTime: option.startTime,
                        relativeDuration: 0.1,
                        animations: {
                            self.ggImg.transform = CGAffineTransform(translationX: option.translationX, y: 0.0)
                                .rotated(by: option.rotated)
                                .scaledBy(x: option.scaledX, y: 1.0)
                            self.ggImg.center = CGPoint(x: 207.0, y: option.centerY)
                        }
                    )
                }
            },
            completion: nil
        )

好摟~通過以上設定
只要執行後 左右跳動的動畫就會不斷循環
跳起來~
讓我們看一下完整的程式碼

import UIKit


struct KeyFrameOptionItem {
    let startTime: Double // 動畫開始時間
    let translationX: CGFloat // 左右位移
    let centerY: Double // 上下跳動
    let rotated: CGFloat // 上下角度
    let scaledX: CGFloat // 水平翻轉
    
    init(startTime: Double, translationX: CGFloat, centerY: Double, rotated: CGFloat, scaledX: CGFloat)  {
        let oneDegree = CGFloat.pi / 180 // 透過pi轉換rotated角度
        self.startTime = startTime
        self.translationX = translationX
        self.rotated = rotated * oneDegree
        self.centerY = centerY
        self.scaledX = scaledX
    }
}

class ViewController: UIViewController {
    // BB~ Label的UI元件參照
    @IBOutlet weak var ggVoice: UILabel!
    //小雞 圖片 參照
    @IBOutlet weak var ggImg: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        setChickAnimation()
    }
    
    // 小雞BB~ Button 被點擊時, 會執行的方法
    @IBAction func ggAction(_ sender: UIButton) {
        ggVoice.text?.append("BB~")
    }
    
    func setChickAnimation() {
        var keyFrameOptions: Array<KeyFrameOptionItem> = []
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.0, translationX: -33.0, centerY: 328.0, rotated: 10, scaledX: 1.0))
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.1, translationX: -66.0, centerY:  348.0, rotated: -10, scaledX: 1.0))
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.2, translationX: -99.0, centerY:  348.0, rotated: 10, scaledX: 1.0))
        // 以上向左邊跳到底後轉身往回走
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.3, translationX: -66.0, centerY:  348.0, rotated: -10, scaledX:  -1.0))
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.4, translationX: -33.0, centerY: 348.0, rotated: 10, scaledX:  -1.0))
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.5, translationX: 0.0,  centerY: 348.0, rotated: -10, scaledX: -1.0))
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.6, translationX: 40.0, centerY:  348.0, rotated: 10, scaledX:  -1.0))
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.7, translationX: 100.0, centerY:  348.0, rotated: -10, scaledX: -1.0))
        //跳到最右邊後 轉身往原點走
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.8, translationX: 40.0, centerY:  348.0, rotated: 10, scaledX:  1.0))
        keyFrameOptions.append(KeyFrameOptionItem(startTime: 0.9, translationX: 0.0, centerY:  348.0, rotated: -10, scaledX: 1.0))
        
        UIView.animateKeyframes(
            withDuration: 4,
            delay: 0.0,
            options: [.repeat],
            animations: {
                for option in keyFrameOptions {
                    UIView.addKeyframe(
                        withRelativeStartTime: option.startTime,
                        relativeDuration: 0.1,
                        animations: {
                            self.ggImg.transform = CGAffineTransform(translationX: option.translationX, y: 0.0)
                                .rotated(by: option.rotated)
                                .scaledBy(x: option.scaledX, y: 1.0)
                            self.ggImg.center = CGPoint(x: 207.0, y: option.centerY)
                        }
                    )
                }
            },
            completion: nil
        )
    }
}

此時只要APP運行
在 viewDidLoad , 就會不斷播放這則動畫了
swift 小雞BB

小碎嘴時間 ヽ(゚´Д`)ノ゚

動起來了!
在做網頁的時候, 只要能讓畫面動起來
整個就大加分~

看到自己畫的小雞跳起來
超級爽Der

真好奇同樣的動畫在Android
會用怎麼樣的寫法

動畫的內容比較多
明天再來一起看看Kotlin的寫法吧


上一篇
[Day16] swift & kotlin 實作篇!(7) Click Event 綁定
下一篇
[Day18] swift & kotlin 實作篇!(9) Animation -kotlin
系列文
雙平台APP小遊戲開發實作! Swift & Kotlin 攜手出擊~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言