Lottiebb 2.5.6

Lottiebb 2.5.6

Richard 维护。



Lottiebb 2.5.6

  • Richard

Lottie for iOS, macOS (以及 AndroidReact Native)

目录

简介

Lottie 是一个适用于 Android 和 iOS 的移动库,它使用 bodymovin 将 Adobe After Effects 动画(以 json 格式导出)解析,并在移动设备和 React Native 中本地渲染矢量动画!

首次,设计师可以创建并发布漂亮的动画,而无需工程师手动辛苦地重新创建它。由于动画由 JSON 支持,它们在大小上极小,但可以具有复杂的结构!动画可以是播放、调整大小、循环、加速、减速、反转,甚至可以交互式拖动。Lottie 也可以只播放或循环动画的一部分,可能性无穷!甚至可以在运行时以各种方式更改动画!更改颜色、位置或任何可关键帧化的值!Lottie 还支持原生 UIViewController 转场功能!

以下只是 Lottie 强大功能的一小部分示例。

Example1 Example2

Example3

Abcs

安装 Lottie

Github 仓库

您可以拉取 Lottie 的 Github 仓库 并包含 Lottie.xcodeproj 以构建一个动态或静态库。

Cocoapods

获取 Cocoapods 并在 podfile 中添加该 pod

pod 'lottie-ios'

执行

pod install

在将 Cocoapod 安装到项目中后,使用 Objective C #import <Lottie/Lottie.h> 或 Swift import Lottie 导入 Lottie

Carthage

获取 Carthage

将 Lottie 添加到 Cartfile

github "airbnb/lottie-ios" "master"

执行

carthage update

在您的应用程序目标的“通用”选项卡下,“链接框架和库”部分,从 carthage update 生成的 Carthage/Build/iOS 目录中拖放 lottie-ios.framework。

iOS 示例应用

克隆此仓库并尝试 示例应用。此仓库可以构建 macOS 示例和 iOS 示例。

iOS 示例应用演示了 Lottie 的多个功能。

Example 1Example 2 Example 3

动画探索器允许您拖动、播放、循环和调整动画的大小。动画可以从应用程序包或使用内置 QR 码读取器从 Lottie Files 加载。

macOS 样例应用

克隆此仓库并尝试 示例应用。此仓库可以构建 macOS 示例和 iOS 示例。

Lottie Viewer

macOS Lottie 查看器允许您拖放 JSON 文件以打开、播放、快进和循环动画。此应用使用与 iOS 应用相同的动画代码,因此您将获得精确的 Mac 和 iOS 动画表示。

Objective-C 示例

可以从打包的 JSON 或从 URL 加载 Lottie 动画。要打包 JSON,只需将其以及动画所需的任何图像添加到 Xcode 的目标中即可。

LOTAnimationView *animation = [LOTAnimationView animationNamed:@"Lottie"];
[self.view addSubview:animation];
[animation playWithCompletion:^(BOOL animationFinished) {
  // Do Something
}];

如果您使用多个打包文件,可以使用。

LOTAnimationView *animation = [LOTAnimationView animationNamed:@"Lottie" inBundle:[NSBundle YOUR_BUNDLE]];
[self.view addSubview:animation];
[animation playWithCompletion:^(BOOL animationFinished) {
  // Do Something
}];

或者,您可以从 NSURL 以编程方式加载它。

LOTAnimationView *animation = [[LOTAnimationView alloc] initWithContentsOfURL:[NSURL URLWithString:URL]];
[self.view addSubview:animation];

Lottie 支持iOS的 UIViewContentModes,包括 aspectFit、aspectFill 和 scaleFill。

您还可以通过交互来设置动画进度。

CGPoint translation = [gesture getTranslationInView:self.view];
CGFloat progress = translation.y / self.view.bounds.size.height;
animationView.animationProgress = progress;

或者,您可以播放动画的某个部分。

[lottieAnimation playFromProgress:0.25 toProgress:0.5 withCompletion:^(BOOL animationFinished) {
  // Do Something
}];

Swift 示例

可以从打包的 JSON 或从 URL 加载 Lottie 动画。要打包 JSON,只需将其以及动画所需的任何图像添加到 Xcode 的目标中即可。

let animationView = LOTAnimationView(name: "LottieLogo")
self.view.addSubview(animationView)
animationView.play{ (finished) in
  // Do Something
}

如果您的动画在另一个打包文件中,您可以。

let animationView = LOTAnimationView(name: "LottieLogo" bundle:yourBundle)
self.view.addSubview(animationView)
animationView.play()

或者,您可以从 URL 异步地加载它。

let animationView = LOTAnimationView(contentsOf: WebURL)
self.view.addSubview(animationView)
animationView.play()

您还可以通过交互来设置动画进度。

let translation = gesture.getTranslationInView(self.view)
let progress = translation.y / self.view.bounds.size.height;
animationView.animationProgress = progress

或者,您可以播放动画的某个部分。

animationView.play(fromProgress: 0.25, toProgress: 0.5, withCompletion: nil)

iOS 视图控制器转换

Lottie 包含一个 UIViewController 动画控制器,用于创建自定义视图控制器转换!

Transition1 Transition2

只需成为转换的代理即可

- (void)_showTransitionA {
  ToAnimationViewController *vc = [[ToAnimationViewController alloc] init];
  vc.transitioningDelegate = self;
  [self presentViewController:vc animated:YES completion:NULL];
}

并使用 LOTAnimationTransitionController 实现代理方法

#pragma mark -- View Controller Transitioning

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
  LOTAnimationTransitionController *animationController = [[LOTAnimationTransitionController alloc] initWithAnimationNamed:@"vcTransition1" fromLayerNamed:@"outLayer" toLayerNamed:@"inLayer" applyAnimationTransform:NO];
  return animationController;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
  LOTAnimationTransitionController *animationController = [[LOTAnimationTransitionController alloc] initWithAnimationNamed:@"vcTransition2" fromLayerNamed:@"outLayer" toLayerNamed:@"inLayer" applyAnimationTransform:NO];
  return animationController;
}

applyAnimationTransform 设置为 YES,可以移动来自和目标视图控制器。它们将位于层的原点。当设置为 NO 时,Lottie 仅使用指定的层遮罩视图控制器,同时尊重 Z 轴顺序。

调试

关于Lottie的调试功能,有一些重要的信息需要了解。当一个动画加载时,不支持的功能会在控制台输出其函数名称。

如果您查看LOTHelpers.h,您将看到两个调试标志。分别是ENABLE_DEBUG_LOGGINGENABLE_DEBUG_SHAPESENABLE_DEBUG_LOGGING增加了Lottie日志的详细程度。它记录任何动画节点在动画过程中被设置的情况。如果您发现动画运行不正常,请开启此功能并播放动画。控制台的日志可能会给出一些关于问题原因的线索。

ENABLE_DEBUG_SHAPES为每个层的锚点绘制一个彩色方块。这有助于看出屏幕上是否有任何东西。

关键路径

LOTAnimationView提供了- (void)logHierarchyKeypaths方法,可以递归记录动画的所有可设置的键路径。这有助于在运行时更改动画。

在运行时向动画中添加视图

使用Lottie,您不仅可以在运行时更改动画,还可以在运行时向LOTAnimation中添加自定义UI。下面的示例展示了如何利用这个功能来创建一个动态图像加载器。

动态图像加载器

Spinner

上面的示例展示了使用单个LOTAnimationView设置加载器动画的情况。当图片异步下载时,加载器循环动画的一部分。当下载完成时,图片被添加到动画中,剩下的动画无缝播放。图片被干净地动画化,并调用完成块。

Spinner_Alt

现在,动画已由设计师更改并需要更新。所有需要做的就是更新包中的JSON文件。无需代码更改!

Spinner_Dark

在此,设计决定为应用程序添加“暗黑模式”。只需几行代码即可在运行时更改动画的颜色。

非常强大吧?

下面提供的代码示例给出了一个示例!

import UIKit
import Lottie

class ViewController: UIViewController {
  
  var animationView: LOTAnimationView = LOTAnimationView(name: "SpinnerSpin");
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    // Setup our animaiton view
    animationView.contentMode = .scaleAspectFill
    animationView.frame = CGRect(x: 20, y: 20, width: 200, height: 200)

    self.view.addSubview(animationView)
    // Lets change some of the properties of the animation
    // We arent going to use the MaskLayer, so lets just hide it
    animationView.setValue(0, forKeypath: "MaskLayer.Ellipse 1.Transform.Opacity", atFrame: 0)
    // All of the strokes and fills are white, lets make them DarkGrey
    animationView.setValue(UIColor.darkGray, forKeypath: "OuterRing.Stroke.Color", atFrame: 0)
    animationView.setValue(UIColor.darkGray, forKeypath: "InnerRing.Stroke.Color", atFrame: 0)
    animationView.setValue(UIColor.darkGray, forKeypath: "InnerRing.Fill.Color", atFrame: 0)
    
    // Lets turn looping on, since we want it to repeat while the image is 'Downloading'
    animationView.loopAnimation = true
    // Now play from 0 to 0.5 progress and loop indefinitely.
    animationView.play(fromProgress: 0, toProgress: 0.5, withCompletion: nil)
    
    // Lets simulate a download that finishes in 4 seconds.
    let dispatchTime = DispatchTime.now() + 4.0
    DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
      self.simulateImageDownloaded()
    }
  }
  
  func simulateImageDownloaded() {
    // Our downloaded image
    let image = UIImage(named: "avatar.jpg")
    let imageView = UIImageView(image: image)

    // We want the image to show up centered in the animation view at 150Px150P
    // Convert that rect to the animations coordinate space
    // The origin is set to -75, -75 because the origin is centered in the animation view
    let imageRect = animationView.convert(CGRect(x: -75, y: -75, width: 150, height: 150), toLayerNamed: nil)
    
    // Setup our image view with the rect and add rounded corners
    imageView.frame = imageRect
    imageView.layer.masksToBounds = true
    imageView.layer.cornerRadius = imageRect.width / 2;
    
    // Now we set the completion block on the currently running animation
    animationView.completionBlock = { (result: Bool) in ()
      // Add the image view to the layer named "TransformLayer"
      self.animationView.addSubview(imageView, toLayerNamed: "TransformLayer", applyTransform: true)
      // Now play the last half of the animation
      self.animationView.play(fromProgress: 0.5, toProgress: 1, withCompletion: { (complete: Bool) in
        // Now the animation has finished and our image is displayed on screen
        print("Image Downloaded and Displayed")
      })
    }
    
    // Turn looping off. Once the current loop finishes the animation will stop 
    // and the completion block will be called.
    animationView.loopAnimation = false
  }
  
}

运行时更改动画

Lottie不仅能播放美观的动画。Lottie还允许您在运行时更改动画。

假设我们要创建4个开关。

Toggle 创建这四个开关并播放它们很简单

let animationView = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView)
animationView.frame.origin.x = 40
animationView.frame.origin.y = 20
animationView.autoReverseAnimation = true
animationView.loopAnimation = true
animationView.play()

let animationView2 = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView2)
animationView2.frame.origin.x = 40
animationView2.frame.origin.y = animationView.frame.maxY + 4
animationView2.autoReverseAnimation = true
animationView2.loopAnimation = true
animationView2.play()

let animationView3 = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView3)
animationView3.frame.origin.x = 40
animationView3.frame.origin.y = animationView2.frame.maxY + 4
animationView3.autoReverseAnimation = true
animationView3.loopAnimation = true
animationView3.play()

let animationView4 = LOTAnimationView(name: "toggle");
self.view.addSubview(animationView4)
animationView4.frame.origin.x = 40
animationView4.frame.origin.y = animationView3.frame.maxY + 4
animationView4.autoReverseAnimation = true
animationView4.loopAnimation = true
animationView4.play()

现在,让我们改变它们的颜色

Recolored Toggle

animationView2.setValue(UIColor.green, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView3.setValue(UIColor.red, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView4.setValue(UIColor.orange, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
[animationView2 setValue:[UIColor greenColor] forKeypath:@"BG-On.Group 1.Fill 1.Color" atFrame:@0];

keyPath是从After Effects中分离的层和属性名称的点分隔路径。LOTAnimationView提供了- (void)logHierarchyKeypaths,它会递归地记录动画的所有可设置的关键路径。Key Path "BG-On.Group 1.Fill 1.Color"

现在,让我们更改一些属性

Multiple Colors

animationView2.setValue(UIColor.green, forKeypath: "BG-On.Group 1.Fill 1.Color", atFrame: 0)
animationView2.setValue(UIColor.red, forKeypath: "BG-Off.Group 1.Fill 1.Color", atFrame: 0)

Lottie允许您更改After Effects中可动画的任何属性。如果不存在关键帧,它将为您创建线性关键帧。如果存在关键帧,则仅仅替换其数据。

动画控件和开关

Animated Buttons

Lottie还有一个用于创建自定义可动画交互控件的UIControl子类。目前,Lottie有LOTAnimatedSwitch,它是一个切换样式开关控件。轻触开关将播放开/关或关/开动画,并向所有目标发出UIControlStateValueChanged广播。它与UISwitch的使用方式相同,只是增加了一些Lottie用于设置动画的方法。

您可以通过便利方法或直接提供动画来初始化开关。

// Convenience
LOTAnimatedSwitch *toggle1 = [LOTAnimatedSwitch switchNamed:@"Switch"];
 
// Manually 
LOTComposition *comp = [LOTComposition animationNamed:@"Switch"];
LOTAnimatedSwitch *toggle1 = [[LOTAnimatedSwitch alloc] initWithFrame:CGRectZero];
[toggle1 setAnimationComp:comp];

您还可以指定动画时间线中的特定部分来实现开启和关闭动画。默认情况下,LOTAnimatedSwitch将正向播放开启动画,反向播放关闭动画。

假设所提供的动画从0.5进度动画到1进度表示开启,从0进度到0.5进度表示关闭。

/// On animation is 0.5 to 1 progress.
[toggle1 setProgressRangeForOnState:0.5 toProgress:1];

/// Off animation is 0 to 0.5 progress.
[toggle1 setProgressRangeForOffState:0 toProgress:0.5];

此外,所有LOT Animated Controls都支持在状态变化时更改外观。这需要在After Effects中做一些设置。Lottie将根据控件状态切换可见的动画图层。这可以用于Disabled、已选择或高亮等状态。这些状态与After Effects中的图层名称相关联,并随着控件状态的变化动态显示。

假设我们有一个具有正常状态和禁用状态的切换开关。在我们的效果中,有一个包含常规“按钮”和禁用“禁用”状态的“预合成”组合。它们的视觉风格不同。

Regular Disabled

现在,在代码中,我们可以将这些图层与UIControlState相关联

// Specify the layer names for different states
[statefulSwitch setLayerName:@"Button" forState:UIControlStateNormal];
[statefulSwitch setLayerName:@"Disabled" forState:UIControlStateDisabled];

// Changes visual appearance by switching animation layer to "Disabled"
statefulSwitch.enabled = NO;

// Changes visual appearance by switching animation layer to "Button"
statefulSwitch.enabled = YES;

支持After Effects功能

关键帧插值


  • 线性插值
  • 贝塞尔插值
  • 保持插值
  • 跨越时间移动
  • 空间贝塞尔

实色


  • 变换锚点
  • 变换位置
  • 变换缩放
  • 变换旋转
  • 变换不透明度

遮罩


  • 路径
  • 不透明度
  • 多个遮罩(加法、减法和相交)

跟踪遮罩


  • Alpha 遮罩

育儿


  • 多重育儿
  • 空值

形状图层


  • 锚点
  • 位置
  • 缩放
  • 旋转
  • 不透明度
  • 路径
  • 组变换(锚点、位置、缩放等)
  • 矩形(所有属性)
  • 圆形(所有属性)
  • 一个组中的多个路径
  • 奇偶交替的路径
  • 反转填充规则

描边(形状图层)


  • 描边颜色
  • 描边不透明度
  • 描边宽度
  • 线帽
  • 虚线(现在动画化!)

填充(形状图层)


  • 填充颜色
  • 填充不透明度

裁剪路径(形状图层)


  • 裁剪路径开始
  • 裁剪路径结束
  • 裁剪路径偏移

重复器


  • 支持重复器变换
  • 当前不支持偏移。

渐变


  • 支持线性渐变
  • 支持径向渐变

多星形和多边形


  • 受支持!如果圆度大于100%,则存在已知错误。

图层功能


  • 预合成
  • 图像图层
  • 形状图层
  • 空图层
  • 纯色图层
  • 父图层
  • 透明度蒙版图层

当前不支持的After Effects功能

  • 合并形状
  • alpha反转蒙版
  • 剪辑路径的“单独剪切形状”特性
  • 表达式
  • 3D图层支持
  • 时间重映射/图层反向
  • 图层混合模式
  • 图层效果

社区贡献

替代方案

  1. 手工构建动画。手工构建动画对于Android和iOS的设计和工程来说是一项巨大的时间投入。通常很难或甚至无法证明花费这么多时间来正确进行动画是合理的。
  2. Facebook Keyframes。Keyframes 是 Facebook 开发的一个用于动画效果的新库。虽然它不支持 Lottie 的某些功能,例如遮罩、毛边、裁剪路径、虚线模式等。
  3. Gif 图像。Gif 图像的大小是 bodymovin JSON 的两倍以上,且以固定大小渲染,无法放大以适应大屏幕和高密度屏幕。
  4. Png 序列。与 Gif 相比,Png 序列的文件大小通常是 bodymovin JSON 的 30-50 倍,也无法放大。

为什么叫 Lottie?

Lottie 命名自一位德国电影导演,她是剪影动画的先驱。她的最著名电影是《阿赫迈德的冒险》(1926)——这是现存最古老的动画长片,比华特·迪士尼的《白雪公主和七个小矮人》(1937)早了十多年,洛蒂·雷尼格的艺术

贡献

欢迎贡献者。只需上传带有更改描述的 PR。

如果您想添加更多 JSON 文件,请自由地这样做!

问题或功能请求?

为任何意外出错的插件提交 GitHub 问题。如果 After Effects 文件不起作用,请将其附加到您的问题中。没有原始文件调试会更加困难。Lottie 由 Brandon Withrow 开发和维护。请随时通过电子邮件或 Twitter 联系。

路线图(不分顺序)

  • 添加支持交互式动画过渡

lottie-ios-bb