MotionMachine 为操纵值提供了一个模块化、强大且通用的平台,无论是动画 UI 元素还是插值您自己类中的属性值。它提供了合理的默认功能,抽象了大部分的困难工作,让您可以专注于自己的工作。虽然它是类型无关的,但 MotionMachine 默认支持大多数主要的 UIKit 类型,并提供了语法糖来轻松操作它们。但也很容易深入人心并对其进行修改以满足您的需求,无论是自定义运动类、支持自定义值类型还是新的缓动方程。
- 从头开始构建的动画引擎(不依赖于 Core Animation)。
- 动作可以分组、排列和嵌套在任何布局中,并且可以在任何级别应用反转和重复操作。
- 可以动画化 UIKit 或任何通用类的属性。
- 包括静态和基于物理的运动类,并且两者都支持加动画。
- 强大的模块化——大多数方面都可以根据您的特定需求进行定制或完全替换。
- 为许多类型的运动事件提供状态回调闭包。
- 完全测试
- 完全 文档化
开始使用
运动类指南 开始使用,以获取详细的说明和示例。
通过还可以查看 示例项目,以查看所有 MotionMachine 类的实际操作,或深入了解 文档。
介绍
这个复杂的动画是用下面的代码示例创建的。这些Motion
类用于动画化圆形视图的NSLayoutConstraints(在target
参数中,约束对象是一个包含NSLayoutConstraint引用的字典),以及它们的其中一个backgroundColor
属性。使用了一个MotionGroup
对象来同步四个Motion
对象并反转它们的移动。
let group = MotionGroup()
.add(Motion(target: constraints["circleX"]!,
properties: [PropertyData("constant", 200.0)],
duration: 1.0,
easing: EasingQuartic.easeInOut()))
.add(Motion(target: constraints["circleY"]!,
properties: [PropertyData("constant", 250.0)],
duration: 1.4,
easing: EasingElastic.easeInOut()))
.add(Motion(target: circle,
properties: [PropertyData("backgroundColor.blue", 0.9)],
duration: 1.2,
easing: EasingQuartic.easeInOut()))
.add(Motion(target: constraints["circle2X"]!,
properties: [PropertyData("constant", 300.0)],
duration: 1.2,
easing: EasingQuadratic.easeInOut())
.reverses(withEasing: EasingQuartic.easeInOut()))
.start()
这是如何工作的?
所有MotionMachine中包含的运动类都采用Moveable
协议,这使得它们能够无缝协作。通过使用MotionGroup
和MotionSequence
集合类来控制多个运动对象(甚至嵌套多层),你可以轻松地创建复杂的动画。
运动
Motion
使用KVC键路径(即“frame.origin.x”)来针对对象的特定属性,并通过缓动方程在一段时间内转换它们的值。在这个例子中,我们通过statesForProperties便利初始化器将PropertyStates
结构体传递给状态,为目标的transform和backgroundColor属性提供结束状态。
let new_color = UIColor.init(red: 91.0/255.0, green:189.0/255.0, blue:231.0/255.0, alpha:1.0)
let circle = circles[0]
motion = Motion(target: circle,
statesForProperties: [
PropertyStates(path: "transform", end: circle.transform.scaledBy(x: 1.5, y: 1.5)),
PropertyStates(path: "backgroundColor", end: new_color)
],
duration: 2.0,
easing: EasingBack.easeInOut(overshoot: 0.5))
.reverses()
.start()
MotionGroup
MotionGroup
是一个管理一组Moveable
对象的MoveableCollection
类,它可以并行控制它们的移动。这在控制和同步多个Moveable
对象时非常有用。MotionGroup
甚至可以控制其他的MoveableCollection
对象。在下面的例子中,我们指示MotionGroup反转并同步其子运动,这样做意味着它将在正向运动完成后暂停所有运动,然后才会反转它们。在这种情况下,水平的运动将暂停,等待修改第二个圆的backgroundColor的Motion完成它的3秒持续时间。
// the MotionGroup will wait for all child motions to finish moving forward before starting their reverse motions
group = MotionGroup().reverses(syncsChildMotions: true)
// move first circle horizontally
let horizontal1 = Motion(target: constraints["x1"]!,
properties: [PropertyData("constant", 250.0)],
duration: 1.5,
easing: EasingSine.easeOut())
.reverses()
group.add(horizontal1)
// reverse and repeat horizontal movement of second circle once, with a subtle overshoot easing
let horizontal2 = Motion(target: constraints["x2"]!,
properties: [PropertyData("constant", 250.0)],
duration: 1.0,
easing: EasingBack.easeOut(overshoot: 0.12))
.reverses()
group.add(horizontal2)
// change backgroundColor of second circle
let color = Motion(target: circles[1],
statesForProperties: [PropertyStates(path: "backgroundColor", end: UIColor.init(red: 91.0/255.0, green:189.0/255.0, blue:231.0/255.0, alpha:1.0))],
duration: 3.0,
easing: EasingQuadratic.easeInOut())
group.add(color)
.start()
运动序列
运动序列
是一个可移动集合
类,以顺序方式移动一组可移动
对象,包括其他可移动集合
对象。运动序列
提供了一种强大且简单的方法,将对象属性的值变换逐一连接起来,以进行关键帧动画或创建复杂流畅的多个物体的组合动画。
// create a reversing MotionSequence with its reversingMode set to contiguous to create a fluid animation from its child motions
sequence = MotionSequence().reverses(.contiguous)
// set up motions for each circle and add them to the MotionSequence
for x in 0..<4 {
// motion to animate a topAnchor constraint down
let down = Motion(target: constraints["y\(x)"]!,
properties: [PropertyData("constant", 60.0)],
duration: 0.4,
easing: EasingQuartic.easeInOut())
// motion to change background color of circle
let color = Motion(target: circles[x],
statesForProperties: [PropertyStates(path: "backgroundColor", end: UIColor.init(red: 91.0/255.0, green:189.0/255.0, blue:231.0/255.0, alpha:1.0))],
duration: 0.3,
easing: EasingQuadratic.easeInOut())
// wrap the Motions in a MotionGroup and set it to reverse
let group = MotionGroup(motions: [down, color]).reverses(syncsChildMotions: true)
// add group to the MotionSequence
sequence.add(group)
}
sequence.start()
安装
如果你使用CocoaPods,在你的Podfile中添加这个pod
Podfile
pod 'MotionMachine', '~> 1.3'
或者将源目录添加到你的项目中。
兼容性
MotionMachine当前需要以下条件:
- Swift 5.0
- Xcode 10.0或更高版本
- iOS 8.0或更高版本,tvOS 9.0或更高版本
注意事项
-
MotionMachine使用键值编码(KVC)来反查对象,并使用键路径检索和设置其属性值。因为Swift目前没有提供这方面的原生功能,因此需要通过MotionMachine修改属性的对象必须继承自
NSObject
。如果Swift在未来增加了更多动态功能(本库的作者希望如此),MotionMachine有望摆脱这种限制。请注意,截至Swift 4.0,任何你希望操作的定制类的属性必须使用@objc
前缀,或者如果你希望所有属性都对外开放,请在类定义上方添加@objcMembers
。 -
因为原生的Swift结构体不能继承自
NSObject
,所以目前不幸的是,Swift结构体不能直接与MotionMachine一起使用,尽管如果你不是直接针对其属性,你可以在键路径中使用它们。 -
NSObject
提供的KVC无法评估可选值。你希望用MotionMachine修改的属性不能是可选的。 -
由于Linux平台缺少Foundation和Core Graphics框架,Swift在当前版本中不支持。
致谢
MotionMachine是由Brett Walker创造的。它是基于作者自己的Objective-C库PMTween的。
许可协议
MotionMachine遵循MIT许可协议。详细信息请参阅LICENSE文件。
如果您在项目中使用了MotionMachine,我会很愿意了解!