如何构造酷炫的物理效果和过场动画效果 - Lottie

如何构造酷炫的物理效果和过场动画效果 - Lottie_第1张图片

Lottie(官网) 是 Airbnb 开源的一个动画框架。Lottie这个名字来自于一名德国导演洛特·赖尼格尔(Lotte Reiniger),她最著名的电影叫作“阿赫迈德王子历险记(The Adventures of Prince Achmed)”。这个框架和其他动画框架不太一样,动画的编写和维护将由动画设计师完成,完全无需开发者操心。

动画设计师做好动画以后,可以使用After Effects将动画导出JSON文件,然后由Lottie加载和渲染这个JSON文件,并转换成对应的动画代码。由于是JSON格式,文件也会很小,可以减少App包大小。运行时还可以通过代码控制更改动画,比如更改颜色、位置以及任何关键值。另外,Lottie还支持页面切换的过场动画(UIViewController Transitions)。

上图的引导图,就是Lottie的加载图效果,其动画就是由动画设计师使用After Effects 创作,然后使用Bodymovin 进行导出的,开发者完全不用做什么额外的代码工作,就能够使用原生方式将其渲染出来。

bodymovin是Hernan Torrisi 做的一个 After Effects的插件,起初导出的JSON文件只是通过JavaScript在网页中进行动画的播放,后来才将JSON文件的解析渲染应用到了其他平台上。

Bodymovin

先去Adobe官网下载Bodymovin插件(如果找不到相关加载则进入这个百度盘去下载AE 插件 & Bodymovin 百度云盘下载地址  密码:zdsh),并在After Effects中安装。使用After Effects制作完动画后,选择Window菜单,找到Extensions的Bodymovin项,在菜单中选择Render按钮就可以输出JSON文件了。

Lottie Files网站还是一个动画设计师分享作品的平台,每个动画效果的JSON文件都可以下载使用。所以,如果你现在没有动画设计师配合的话,可以到这个网站去查找并下载一个Bodymovin生成的JSON文件,然后运用到工程中去试试效果。

在iOS中使用Lottie

在iOS开发中使用Lottie也很简单,只要集成Lottie框架,然后在程序中通过Lottie的接口控制After Effects 生成的动画JSON就行了。

首先,你可以通过CocoaPods集成Lottie框架到你工程中。Lottie iOS框架的GitHub地址是https://github.com/airbnb/lottie-ios,官方也提供了demo。

然后,快速读取一个由 Bodymovin 生成的 JSON 文件进行播放。具体代码:

let animationTestView = AnimationView()                                                                             let animationTest = Animation.named("loader2")                                                                 animationTestView.animation = animationTest                                                view.addSubview(animationTestView)                                                                              animationTestView.play()


利用Lottie的动画进度控制能力,还可以完成手势与动效同步的问题。动画进度控制是:

animationTestView.play(fromProgress: 0,

toProgress : 1,

loopMode: LottieLoopMode.playOnce,

completion: {(finished)  in

if finished {

print("Animation Complete")

} else {

print("Animation cancelled")

}

})



Lottie还带有一个UIViewController  animation-controller,可以自定义页面切换的过场动画,等。

Lottie在运行期间提供接口和协议来更改动画,有动画数据搜索接口LOTKeyPath,以及设置动画数据的协议LOTValueDelegate。详细的说明和使用实例代码,可以参照官方iOS教程。

多平台支持

Lottie支持多平台,除了支持iOS,还支持Android,React Native 和Flutter。除了官方维护的这些平台外,Lottie还支持Windows,Qt,Skia。陈卿还实现了Rect、Vue和Angular对Lottie的支持,并已将代码放到GitHub上。

Lottie 实现原理

实际上,Lottie iOS在iOS内做的事情就是将After Effects编辑的动画内容,通过JSON文件这个中间媒介,一一映射到iOS的LayerModel、Keyframe、ShapeItem、DashElement、Marker、Mask、Transform这些类的属性中并保存下来,接下来再通过CoreAnimation进行渲染。这就和你手动写动画代码的实现是一样的,只不过这个过程的精准描述,全部由动画设计师通过JSON文件输入进来。

Lottie iOS使用系统自带的Codable协议来解析JSON文件,这样就可以享受系统升级带来性能提升的便利,比如ShapeItem这个类设计如下:

//Shape Layer

class ShapeItem:Codable {

/// shape 的名字

let name: String

///shape的类型

let type: ShapeType

//和json 中字符映射

private enum CodingKeys : string, CodingKey {

case name = "nm"

case type = "ty"

}

//初始化

required init(from decoder:Decoder)throws {

let container = try decoder.container(keyedBy:shapeItem.CodingKeys.self)

self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? "Layer"

self.type = try container.decode(ShapeType.self,forKey: .type)

}

}


通过上面代码可以看出,ShapeItem有两个属性,映射到JSON的字符键值是nm和ty,分别代表shape的名字和类型。下面,我们再一起看一段Bodymovin生成的JSON代码:

{"ty":"st","fillEnabled":true,"c":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":22,"s":[0,0.65,0.6,1],"e":[0.76,0.76,0.76,1]},{"t":36}]},"o":{"k":100},"w":{"k":3},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"}


在这段JSON代码中,nm键对应的值是Stroke 1,ty键对应的值是st。那我们再来看看,st是什么类型。

我们知道,ShapeType是个枚举类型,它的定义如下:

enum ShapeType:String, Codable {

case ellipse = "el"

case fill = "fl"

case gradientFill = "gf"

case group = "gr"

case gradientStroke = "gs"

case merge = "mm"

case rectangle = "rc"

case repeater = "rp"

case round = "rd"

case shape = "sh"

case star = "sr'

case stroke = "st"

case trim =  "tm"

case transform = "tr"

}

通过上面的枚举定义,可以看到st对应的是stroke类型。


Lottie就是通过这种方式,定义了一系列的类结构,可以将JSON数据全部映射过来。所有映射用的类都放在Lottie的Model目录下。使用CoreAnimation渲染的相关代码都在NodeRenderSystem目录下,比如前面举例的Stoke。

在渲染前会生成一个节点,实现StrokeNode.swift里,然后对StokeNode这个节点渲染的逻辑在StrokeRenderer.swift里。核心代码如下:

//设置 Context

func setuoForStroke(_ inContext: CGContext) {

inContext.setLineWidth(width) //行宽

inContext.setMiterLimit(miterLimit)

inContext.setLineCap(lineCap.cgLineCap) // 行间隔

inContext.setLineJoin(lineJoin.cgLineJoin)  //设置线条样式

if let dashPhase = dashPhase, let lengths = dashLengths {

inContext.setLineDash(phase: dashPhase, lengths: lengths)

} else {

inContext.setLineDash(phase: 0, lengths: [])

}

}

//渲染

func render (_ inContext : CGContext) {

guard inContext.path != nil && inContext.path !. isEmpty == false  else {

return 

}

guard let color = color else  {  return  }

hasUpdate = false

setupForStroke(inContext)

inContext.setAlpha(opacity) //设置透明度

inContext.setStrokeColor(color)  //设置颜色

inContext.strokePath()

}

如果是手写动画,这些代码就需要不断重复地写。使用第三方库去写动画的话,也无非是多封装了一层,而属性的设置、动画时间的设置等,还是需要手动添加很多代码来完成的。

但是,使用Lottie后,就可以完全不需要管理这些代码,只需要在After Effects那设置属性,控制动画时间 就好,当然也可以在代码里面进行设置。

我写的一个 demo 可以进行相关的学习。如果喜欢,可以给颗星,谢谢

你可能感兴趣的:(如何构造酷炫的物理效果和过场动画效果 - Lottie)