Android 和 React Native)
Lottie for iOS, macOS (以及目录
- 简介
- 安装 Lottie
- iOS 示例应用
- macOS 示例应用
- Objective C 示例
- Swift 示例
- 调试 Lottie
- iOS 视图控制器转场
- 运行时更改动画
- 动画控件和开关
- 向动画中添加子视图
- 支持的 After Effects 功能
- 当前不支持的 After Effects 功能
- 社区贡献
- 替代方案
- 为什么叫 Lottie?
- 贡献
- 问题或功能请求?
简介
Lottie 是一个适用于 Android 和 iOS 的移动库,它使用 bodymovin 将 Adobe After Effects 动画(以 json 格式导出)解析,并在移动设备和 React Native 中本地渲染矢量动画!
首次,设计师可以创建并发布漂亮的动画,而无需工程师手动辛苦地重新创建它。由于动画由 JSON 支持,它们在大小上极小,但可以具有复杂的结构!动画可以是播放、调整大小、循环、加速、减速、反转,甚至可以交互式拖动。Lottie 也可以只播放或循环动画的一部分,可能性无穷!甚至可以在运行时以各种方式更改动画!更改颜色、位置或任何可关键帧化的值!Lottie 还支持原生 UIViewController 转场功能!
以下只是 Lottie 强大功能的一小部分示例。
安装 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 的多个功能。
动画探索器允许您拖动、播放、循环和调整动画的大小。动画可以从应用程序包或使用内置 QR 码读取器从 Lottie Files 加载。
macOS 样例应用
克隆此仓库并尝试 示例应用。此仓库可以构建 macOS 示例和 iOS 示例。
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
动画控制器,用于创建自定义视图控制器转换!
只需成为转换的代理即可
- (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_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不仅能播放美观的动画。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];
此外,所有LOT Animated Controls都支持在状态变化时更改外观。这需要在After Effects中做一些设置。Lottie将根据控件状态切换可见的动画图层。这可以用于Disabled、已选择或高亮等状态。这些状态与After Effects中的图层名称相关联,并随着控件状态的变化动态显示。
假设我们有一个具有正常状态和禁用状态的切换开关。在我们的效果中,有一个包含常规“按钮”和禁用“禁用”状态的“预合成”组合。它们的视觉风格不同。
现在,在代码中,我们可以将这些图层与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图层支持
- 时间重映射/图层反向
- 图层混合模式
- 图层效果
社区贡献
- Xamarin绑定
- NativeScript绑定
- Appcelerator Titanium绑定
- 由Alex Pawlowski添加macOS支持
替代方案
- 手工构建动画。手工构建动画对于Android和iOS的设计和工程来说是一项巨大的时间投入。通常很难或甚至无法证明花费这么多时间来正确进行动画是合理的。
- Facebook Keyframes。Keyframes 是 Facebook 开发的一个用于动画效果的新库。虽然它不支持 Lottie 的某些功能,例如遮罩、毛边、裁剪路径、虚线模式等。
- Gif 图像。Gif 图像的大小是 bodymovin JSON 的两倍以上,且以固定大小渲染,无法放大以适应大屏幕和高密度屏幕。
- Png 序列。与 Gif 相比,Png 序列的文件大小通常是 bodymovin JSON 的 30-50 倍,也无法放大。
为什么叫 Lottie?
Lottie 命名自一位德国电影导演,她是剪影动画的先驱。她的最著名电影是《阿赫迈德的冒险》(1926)——这是现存最古老的动画长片,比华特·迪士尼的《白雪公主和七个小矮人》(1937)早了十多年,洛蒂·雷尼格的艺术
贡献
欢迎贡献者。只需上传带有更改描述的 PR。
如果您想添加更多 JSON 文件,请自由地这样做!
问题或功能请求?
为任何意外出错的插件提交 GitHub 问题。如果 After Effects 文件不起作用,请将其附加到您的问题中。没有原始文件调试会更加困难。Lottie 由 Brandon Withrow 开发和维护。请随时通过电子邮件或 Twitter 联系。
路线图(不分顺序)
- 添加支持交互式动画过渡