Swift动画 —— Lottie

3,058 阅读3分钟

这是我参与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)
  }
}