android高级安卓中级进阶codeER.tec

lottie介绍及使用相关(翻译)

2018-04-04  本文已影响2570人  拿根针尖对麦芒
Lottie.jpg

Overview

因为应用的下个版本的很多交互是参考Airbnb来的,而Airbnb开源了一个叫做Lottie动画库,而该库可以完成很多复杂炫酷的动画。所以在此翻译了Lottie的相应文档,熟悉其API。

通过阅读代码和Demo可以看出,Lottie是及其优秀的。它通过AE做成的动画导出JSON文件,然后前端使用Lottie直接加载JSON文件生成动画,不需要前端进行复杂的绘制等操作。同时Lottie 不仅支持iOS,还支持Mac、Android、web、React Native。而且它还具有占用内存少,加载流畅等特点,是个极其不错的第三方库。

相应文档

Lottie for iOS, macOS (and Android and React Native)

目录

Introduction

Lottie是Android和iOS的移动库,用bodymovin解析Adobe After Effects导出为json的动画并在移动设备上生成矢量动画,适用于React Native!

这是第一次,设计师可以创建和发送漂亮的动画,无需程序员辛苦地手动去创建它.
由于动画由JSON驱动,因此它们的体积非常小,但复杂程度可能很高!
可以播放动画,调整大小,循环,加快速度,减慢速度,颠倒速度,甚至交互式地清理动画。
Lottie也可以播放或循环动画的一部分,可能性是无限的!
动画甚至可以 在运行时以各种方式更改 改变颜色,位置或任何关键的可变值。
Lottie也支持原生的UIViewController Transitions!

这只是Lottie能力的一小部分

Example1
Example2

<img src="https://img.haomeiwen.com/i1388397/3b2a4d25296cdabd.gif?imageMogr2/auto-orient/strip" />

Example3 Abcs

Installing Lottie

Github Repo

您可以下载Lottie Github Repo和其中的Lottie.xcodeproj以构建动态或静态库。

Cocoapods

Get Cocoapods
Add the pod to your podfile

pod 'lottie-ios'

run

pod install

通过CocoaPods安装到你的项目中后,将Lottie头文件导入工程中
Objective C
#import <Lottie/Lottie.h>
Swift
import Lottie

Carthage

Get Carthage

将 Lottie 添加到 Cartfile 中

github "airbnb/lottie-ios" "master"

run

carthage update

在你的应用程序的“常规”选项卡中“链接的框架和库”,需要从Carthage / Build / iOS目录中拖放“carthage update”生成的lottie-ios.framework。

iOS Sample App

克隆这个repo,并尝试示例应用程序,
repo中包含了一个macOS示例和一个iOS示例

iOS示例应用程序演示了Lottie的几项功能

Example 1 Example 2
Example 3

动画资源管理器允许您移除,播放,循环和调整动画大小。
可以使用内置的扫描功能从应用程序包或从Lottie文件中加载动画。

macOS Sample App

下载这个 repo 并尝试运行 the Sample App,
这个repo可以构建一个macOS示例和一个iOS示例

Lottie Viewer

用于macOS的Lottie Viewer允许您拖放JSON文件用于播放,移除和循环动画。 Mac程序和iOS程序的动画代码是一样的,因此您将获得精确的Mac和iOS动画。

Objective C Examples

Lottie可以从Build中的JSON文件或URL中加载动画

如何使用JSON文件加载动画,只需将生成的JSON文件添加到xcode的工程目录下。

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

如果你需要使用bundles中的JSON文件,加载动画

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支持iOSUIViewContentModes的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 Examples

Lottie可以从Bundle中的JSON文件或URL中加载动画

如何使用JSON文件加载动画,只需将生成的JSON文件添加到xcode的工程目录中。

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

如果你需要使用bundles中的JSON文件,加载动画

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

或者你可以通过NSURL以编码的方式加载动画

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 View Controller Transitioning

Lottie带有一个UIViewController动画控制器,用于制作自定义viewController转换!

Transition1
Transition2

只是成为过渡的delegate

- (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,您可以使Lottie动画从一个视图控制器移动到另一个视图控制器。 它们将定位在图层的起源处。 设置为NO时,Lottie只是在指定z层时遮蔽具有指定层的视图控制器。

Debugging

Lottie有几个要了解的调试功能。
当加载动画时,不支持的功能,其工程名将打印在控制台中。

如果您查看LOTHelpers.h这个类,您将看到两个调试标志。 ENABLE_DEBUG_LOGGINGENABLE_DEBUG_SHAPES
ENABLE_DEBUG_LOGGING增加了Lottie Logging的详细程度。 它在动画期间随时记录一个动画节点。 如果您的动画不起作用,请将其打开并播放您的动画。 控制台日志可能会给你一些关于问题什么的线索。

ENABLE_DEBUG_SHAPES为每个图层和形状的锚点画一个彩色正方形。 这对查看屏幕上是否有任何内容很有帮助。

Keypaths

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

Adding Views to an Animation at Runtime

您不仅可以(在运行时更改动画),还可以在运行时将自定义UI添加到LOTAnimation中。
下面的例子是一些进度用途的动态图像加载器。

A Dynamic Image Loading Spinner

Spinner

上面的例子显示了一个单独的LOTAnimationView,它使用加载微调器动画进行设置。 加载微调器会循环一部分动画,而图像则是异步下载的。 下载完成后,图像将添加到动画中,其余动画将无缝播放。 图像完美地执行动画并被调用。

Spinner_Alt

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

Spinner_Dark

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

很强大吧 嗯?

查看下面的代码以获取示例!


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
  }
  
}

Changing Animations At Runtime

Lottie可以做的不仅仅是美丽的动画。 Lottie允许您在运行时更改动画

Say we want to create 4 toggle switches.

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()

Now lets change their colors

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"

Now lets change a couple of properties

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 Controls and Switches

Animated Buttons

Lottie还拥有UIControl的自定义子类,用于创建自定义动画式交互式控件。
目前Lottie有LOTAnimatedSwitch这是一种切换式开关控制。 点击开关将播放On-Off或Off-On动画,并向所有目标发送UIControlStateValueChanged广播。 它跟UISwitch使用方式相同,同时使用Lottie设置了一些动画。

您可以使用conveneince方法或直接提供动画来初始化开关。

// 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];

此外,所有LOTAnimatedControls都支持更改状态更改的外观。 这需要After Effects中的一些设置。 Lottie会根据控件状态切换可见的动画图层。 这可以用于具有禁用,选定或突出显示的状态。 这些状态与After Effects中的图层名称关联,并在控件更改状态时动态显示。

可以说我们有一个正常和禁用状态的切换开关。 在效果中,我们有一个包含常规“按钮”和禁用“禁用”状态的Precomps的组合。 他们有不同的视觉风格。

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;

Supported After Effects Features

Keyframe Interpolation


Solids


Masks


Track Mattes


Parenting


Shape Layers


Stroke (shape layer)


Fill (shape layer)


Trim Paths (shape layer)


Repeaters


Gradients


Polystar and Polygon


Layer Features


Currently Unsupported After Effects Features

Community Contributions

Alternatives

  1. 手动构建动画。 手动构建动画是跨Android和iOS设计和工程的时间承诺。 通常很难甚至不可能证明花费这么多时间来获得动画是正确的。
  2. [Facebook关键帧](https://github.com/facebookincubator/Keyframes)。 关键帧是来自Facebook的精彩新图书馆,它们为反应而构建。 但是,关键帧不支持Lottie的一些功能,如遮罩,遮罩,修剪路径,破折号图案等。
  3. Gifs。 GIF的尺寸是bodymovin JSON尺寸的两倍多,并且以固定的尺寸渲染,无法放大以匹配大屏幕和高密度屏幕。
  4. Png序列。 Png序列比gifs更糟,因为它们的文件大小通常是bodymovin json大小的30-50倍,也不能放大。

Why is it called Lottie?

Lottie(洛蒂)是以德国电影导演和剪影动画的先驱者命名的。 她最着名的电影是“阿彻梅德王子历险记”(1926年) - 这是迄今为止最古老的长篇动画电影,在沃尔特迪斯尼的长篇白雪公主和七个小矮人(1937)之前超过十年
The art of Lotte Reineger

Contributing

贡献者非常欢迎。 只需上传一份描述您所做更改的公关。

如果你想添加更多的JSON文件,请随时这样做!

Issues or feature requests?

文件github问题的任何意外中断。 如果After Effects文件无效,请将其附加到您的问题中。 在没有原始文件的情况下进行调试要困难得多。 Lottie由[Brandon Withrow]开发和维护(mailto:brandon.withrow@airbnb.com)。 请随时通过电子邮件或[Twitter](https://twitter.com/theWithra

Roadmap (In no particular order)

上一篇下一篇

猜你喜欢

热点阅读