Android 和 React Native)
Lottie for iOS, macOS (以及目录
- 简介
- 安装 Lottie
- iOS 样本应用
- macOS 样本应用
- Objective-C 示例
- Swift 示例
- 调试 Lottie
- iOS 视图控制器转换
- 运行时更改动画
- 动画控件和开关
- 将子视图添加到动画
- 支持的 After Effects 功能
- 当前不支持的功能
- 社区贡献
- 替代方案
- 为什么叫 Lottie?
- 贡献
- 问题或功能请求?
简介
Lottie 是一个适用于 Android 和 iOS 的移动库,它通过 Adobe After Effects 以 json 格式导出并使用 bodymovin 解析,然后在移动端和通过 React Native 上原生渲染矢量动画!
首次,设计师可以创建并运输美观的动画,无需工程师费尽周折地手工重现。由于动画由JSON支持,它们体积极小,但在复杂度方面却可以很大!动画可以播放、调整大小、循环、加速、减速、逆放,甚至可以交互式刮擦。Lottie还可以播放或循环动画的任一部分,可能性无穷!甚至可以在运行时以各种方式更改动画!改变颜色、位置或任何可关键帧化的值!Lottie还可以默认支持原生UIViewController转换!
这只是展示了Lottie的强大功能的一小部分
安装Lottie
GitHub 代码库
您可以从Lottie GitHub代码库克隆源代码,并将Lottie.xcodeproj添加以构建动态库或静态库。
CocoaPods
获取CocoaPods,并将pod添加到您的Podfile中
pod 'lottie-ios'
运行
pod install
将 Cocoapod 安装到项目中后,导入Lottie(Objective-C:使用 #import <Lottie/Lottie.h>
;Swift: 使用 import Lottie
)
Carthage
获取Carthage
在Cartfile中添加Lottie
github "airbnb/lottie-ios" "master"
运行
carthage update
在应用程序的目标中,“常规”选项卡下,“链接框架和库”部分,从Carthage/Build/iOS目录拖拽lottie-ios.framework到由carthage update
生成的框架中。
iOS示例应用程序
克隆此仓库并尝试运行示例应用程序。此仓库可以构建macOS示例和iOS示例。
iOS示例应用程序演示了Lottie的多个功能
动画浏览器允许您刮擦、播放、循环和调整动画的大小。可以从应用程序包或使用内置二维码扫描仪从Lottie Files加载动画。
macOS示例应用程序
克隆此仓库并尝试运行示例应用程序。此仓库可以构建macOS示例和iOS示例。
macOS版Lottie查看器允许您将JSON文件拖放以打开、播放、刮擦和循环动画。该应用程序使用与iOS应用程序相同的动画代码,因此您将获得Mac和iOS动画的准确表示。
Objective-C示例
Lottie动画可以从捆绑的JSON或从URL加载。要将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
属性, аспектFit、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示例
Lottie动画可以从捆绑的JSON或从URL加载。要将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提供了一个用于制作自定义viewController转换的UIViewController
动画控制器!
只需成为转换的代理
- (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动画移动from和to视图控制器。它们将位于层的原点位置。当设置为NO时,Lottie只是使用指定的层来遮罩视图控制器,同时尊重Z秩序。
调试
Lottie有几个调试功能需要了解。当加载动画时,不支持的功能会以其函数名记录在控制台。
如果你查看LOTHelpers.h,你会看到两个调试标志。ENABLE_DEBUG_LOGGING
和ENABLE_DEBUG_SHAPES
。ENABLE_DEBUG_LOGGING
增加了Lottie日志的详尽程度。它在动画过程中设置动画节点时记录日志。如果你的动画不起作用,请打开它并播放动画。控制台日志可能会给你一些线索。
ENABLE_DEBUG_SHAPES
为每个层和形状的锚点绘制一个彩色的正方形。这有助于查看屏幕上是否有任何内容。
属性路径
LOTAnimationView提供了- (void)logHierarchyKeypaths
,这将递归记录动画的所有可设置属性路径。这对于在运行时更改动画非常有帮助。
在运行时向动画添加视图
您不仅可以使用Lottie在运行时更改动画,还可以在运行时向LOTAnimation添加自定义UI。下面的示例展示了如何创建动态图像加载器的一些高级用法。
动态图像加载器
上述示例显示了设置为加载旋转动画的单个LOTAnimationView。当异步下载图像时,加载旋转动画会循环动画的一部分。下载完成后,图像被添加到动画中,动画的其余部分无缝播放。画面过渡动画流畅,并调用完成块。
现在,动画已被设计师更改,需要进行更新。只需更新包中的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
}
}
运行时更改动画
Lottie不仅可以播放漂亮的动画,还允许您在运行时更改动画。
假设我们想要创建4个切换开关。
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()
现在我们来更改它们的颜色
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
,它将递归记录动画中所有可设置的关键路径。 "BG-On.Group 1.Fill 1.Color"
现在让我们更改一些属性
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中任何可动画化的属性。如果没有关键帧,则会为您创建线性关键帧。如果存在关键帧,则替换其数据。
动画控制和开关
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];
此外,所有的 LOTAnimatedControls 支持更改属性以适应状态变化。这需要在 After Effects 中进行一些设置。Lottie 会根据控件状态切换可见的动画图层。这可以用来有禁用、选中或高亮状态的显示。这些状态与 After Effects 中的图层名称相关联,并且随着控件状态的变化而动态显示。
比如说我们有一个 Normally 状态和禁用 Disabled 状态的切换开关。在效果中,我们有一个包含通常的“按钮”和禁用的“Disabled”状态的前 compounded 合成。它们有不同的视觉样式。
现在在代码中,我们可以将这些 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 percent,则存在一个已知的错误。
图层特性
- 预合成
- 图像图层
- 形状图层
- 空图层
- 纯色图层
- 父图层
- Alpha透明图层
当前不支持After Effects功能
- 合并形状
- Alpha反转蒙版
- 修剪路径的修剪形状功能
- 表达式
- 3D图层支持
- 时间映射/图层倒置
- 图层混合模式
- 图层效果
社区贡献
备选方案
- 手动创建动画。在 Android 和 iOS 上手动创建动画,对于设计和工程来说是一项巨大的时间投入。通常很难,甚至无法证明如此大量的时间能够正确地完成一个动画。
- Facebook Keyframes。Keyframes 是 Facebook 为表情构建的一个新库。然而,Keyframes 并不支持 Lottie 的某些功能,如蒙版、遮罩、裁剪路径、虚线模式等。
- Gif。Gif 的大小是 bodymovin JSON 的大两倍,以固定大小渲染,无法放大以匹配大型和高密度屏幕。
- Png 序列。Png 序列的文件大小通常比 bodymovin JSON 的文件大小大 30-50 倍,并且也不能放大。
为什么叫 Lottie?
Lottie 以德国电影导演、剪影动画的先驱命名。她最著名的电影是《阿赫迈德王子历险记》(1926)——这是现存最古老的长篇动画电影,比华特·迪士尼的《白雪公主和七个小矮人》(1937)早了十多年 Lotte Reineger 的艺术
贡献
非常欢迎贡献者。只需上传一个带有变更描述的 PR 即可。
如果您想添加更多 JSON 文件,请随时添加!
问题或功能请求?
为任何意外损坏的功能提交 GitHub 上的 issues。如果 After Effects 文件不起作用,请将其附加到问题中。没有原始文件进行调试要困难得多。Lottie 由 Brandon Withrow 开发和维护。您可以通过电子邮件或 Twitter 联系他。
路线图(不分先后顺序)
- 支持交互式动画过渡