[Day17] swift & kotlin 实作篇!(8) Animation - swift

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的写法吧


<<:  docker上建立测试环境DVWA

>>:  Day 10- 物品借用纪录系统 (2) 设定 Calendar

day 30 - 结语

这30天大略的纪录了平常我在开发过程会使用到的项目, 从开始选用工具到应用工具的分享, 只是我初步设...

[day23]Vue实作-交易建立页面-API串接问题处理

差点开天窗了,交易建置API呼叫一直有问题。 本来已经要先PO文说明问题了,让我们看下去吧 串接永丰...

CSS-Model 盒模型

前言 在HTML中每一个元素都会被CSS当作一个矩形盒子,CSS可以更改其宽度、高度、跟其他元素的距...

Day24,试着用rancher交差Dashboard

正文 今天要来一日体验rancher server上的dashboard功能 使用racher2.6...

【Day18】在使用者模式移除data-test属性,浅谈React Hook (•‿•)

上一篇有提到,我们可以在使用者模式(Production mode)将属性隐藏起来不让使用者看到。 ...