这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战
Lottie
除了Lottie和图像序列方法,我们还可以使用GIF,视频,甚至可以使用贝塞尔路径或者UIView动画功能的组合来实现。但是相对其他方式来说,Lottie一种比较好的方式来实现动画。
PNG序列图像
PNG序列图形的最大缺点之一是它们的尺寸相当大,这使得它们在不同的界面上导出和操作有些麻烦。 相比之下,Lottie文件非常小,大小也很方便,因此下载速度很快,并尽可能保持网站或应用程序运行的流畅。
GIF格式
虽然比PNG图形小,但gif仍然是一种非常占用空间的格式,平均尺寸是Lottie的两倍。 gif通常也是按固定大小缩放的。这意味着不能对它们进行修改,以更好地适应与最初创建它们的界面不同的界面。Lottie动画则可以进行调整以适应各种规模的屏幕。
录像
关于简单而简短的动画,视频内容经常出现。对于视频内容,尤其是真人版的内容,你需要安排大量的资源,包括道具、演员和地点。动画是相对简单和便宜的选择,仍然可以完成工作。 就编码而言,处理视频要比动画视图(它和UIImageView一样简单)麻烦得多。更不用说:一部好的动画能让你的访问者保持专注,不会强迫他们关掉它。
代码动画
应用程序开发团队希望简化开发过程,使其尽可能具有成本效益或资源效益。 用代码编写动画可能是一个时间和技能密集型的过程,并且在编写代码时容易遇到大量问题。与其将宝贵的资源用于外包项目或雇佣熟练的员工,为什么不使用Lottie替代动画工具,该工具直观、可扩展且兼容多个平台?
这个是我们这次想要达成的效果。
首先声明一个imageView,并且声明想要的imageView大小。
private let sequenceSize: CGSize = CGSize(width: 100, height: 100)
private var sequenceImageView: UIImageView!
创建一个setupUI方法然后在viewDidLoad里面调用。在setupUI里面设置好sequenceImageView的属性,然后添加为view的subview,并且添加一个backButton用来返回到之前的页面(之前的登陆动画页面)。
private func setupUI() {
self.view.backgroundColor = .white
sequenceImageView = UIImageView(frame: CGRect(
origin: CGPoint(x: view.center.x - sequenceSize.width/2,
y: view.center.y - sequenceSize.height/2),
size: sequenceSize))
sequenceImageView.contentMode = .scaleToFill
self.sequenceImageView.image = UIImage(named: "loading_icon")
view.addSubview(sequenceImageView)
let backButton = UIButton(frame: CGRect(x: 16,
y: 40,
width: 44,
height: 44))
backButton.addTarget(self,
action: #selector(userAskToGoBack),
for: .touchUpInside)
backButton.setImage(UIImage(named: "close_icon"), for: .normal)
view.addSubview(backButton)
}
@objc private func userAskToGoBack() {
self.dismiss(animated: true, completion: nil)
}
我们运用Image Sequence 来进行加载图片的动画。添加一个animateSequenceImages方法用来调用,并且在viewDidLoad里面调用这个方法。这里用animationImages来接受所有的图片,然后设置动画时间5s,不重复动画,然后开始动画,动画结束后消失并且调用闭包。
private func animateSequenceImages(completion: @escaping ()->Void) {
let imageSetURL = Bundle.main.urls(
forResourcesWithExtension: "png",
subdirectory: "Sequence")!.sorted(by: { url1, url2 -> Bool in
return url1.lastPathComponent < url2.lastPathComponent
})
sequenceImageView.animationImages = imageSetURL.map{
UIImage(contentsOfFile: $0.path)!
}
sequenceImageView.animationDuration = 5
sequenceImageView.animationRepeatCount = 0
sequenceImageView.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
UIView.animate(withDuration: 0.35, animations: {
self.sequenceImageView.alpha = 0.0
}, completion: { _ in
self.sequenceImageView.alpha = 0.0
})
completion()
})
}
引用 Lottie,然后创建一个AnimationView;
private var giftView: AnimationView!
在setupView里面初始化,并且alpha设为0,让其隐藏,往复播放并且添加为子view。
giftView = AnimationView(name: "bird")
giftView.frame = self.view.frame
giftView.contentMode = .scaleAspectFit
giftView.alpha = 0
giftView.loopMode = .autoReverse
view.addSubview(giftView)
添加animateGift方法来增加显示AnimationView的动画,并且动画结束之后开始播放,并将animateGift方法放在animateSequenceImages闭包里面。
private func animateGift() {
UIView.animate(withDuration: 0.35, animations: {
self.giftView.alpha = 1.0
}, completion: { _ in
self.giftView.play()
})
}
到这里一个简单的Lottie 动画就完成啦。 完整代码
import UIKit
import Lottie
class GiftViewController: UIViewController {
private let sequenceSize: CGSize = CGSize(width: 100, height: 100)
private var sequenceImageView: UIImageView!
private var giftView: AnimationView!
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
animateSequenceImages {
self.animateGift()
}
}
private func setupUI() {
sequenceImageView = UIImageView(frame: CGRect(origin: CGPoint(x: view.center.x - sequenceSize.width/2,
y: view.center.y - sequenceSize.height/2),
size: sequenceSize))
sequenceImageView.contentMode = .scaleToFill
self.sequenceImageView.image = UIImage(named: "loading_icon")
view.addSubview(sequenceImageView)
giftView = AnimationView(name: "bird")
giftView.frame = self.view.frame
giftView.contentMode = .scaleAspectFit
giftView.alpha = 0
giftView.loopMode = .autoReverse
view.addSubview(giftView)
let backButton = UIButton(frame: CGRect(x: 16, y: 40, width: 44, height: 44))
backButton.addTarget(self, action: #selector(userAskToGoBack), for: .touchUpInside)
backButton.setImage(UIImage(named: "close_icon"), for: .normal)
view.addSubview(backButton)
}
private func animateSequenceImages(completion: @escaping ()->Void) {
let imageSetURL = Bundle.main.urls(forResourcesWithExtension: "png", subdirectory: "Sequence")!.sorted(by: { url1, url2 -> Bool in
return url1.lastPathComponent < url2.lastPathComponent
})
sequenceImageView.animationImages = imageSetURL.map{ UIImage(contentsOfFile: $0.path)! }
sequenceImageView.animationDuration = 5
sequenceImageView.animationRepeatCount = 0
sequenceImageView.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
UIView.animate(withDuration: 0.35, animations: {
self.sequenceImageView.alpha = 0.0
}, completion: { _ in
self.sequenceImageView.alpha = 0.0
})
completion()
})
}
private func animateGift() {
UIView.animate(withDuration: 0.35, animations: {
self.giftView.alpha = 1.0
}, completion: { _ in
self.giftView.play()
})
}
@objc private func userAskToGoBack() {
self.dismiss(animated: true, completion: nil)
}
}