动力库 1.1.2

动力库 1.1.2

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布最后发布2019年2月
SPM支持SPM

尼古拉斯·希普斯维护。




动力库 1.1.2

  • 尼古拉斯·希普斯

Version License Platform Total Downloads CI Status

动力库

一个受< Và GSAP启发的、超级灵活的iOS动画库。

要求

  • iOS 9.0+
  • Swift 3.0+
  • Xcode 8+

使用方式

以下文档旨在提供如何与库交互以及当前支持的各项功能的总体概述。为了更好地演示如何使用此库,请务必查阅示例项目提供的代码。要运行示例项目,请克隆仓库,打开Kinetic.xcworkspace,并运行Kinetic-Example项目。

安装

  • CocoaPods:在您的Podfile中添加pod "Kinetic"
  • Carthage:在您的Cartfile中添加github "u10int/Kinetic" "master"

特性

  • 快速设置受 TweenMax、TimelineMax 和 GreenSock 启发的语法动画
  • 在运行时开始、停止、暂停和恢复任何动画
  • 提供缓和和弹簧,制作更真实和有趣的动画
  • 链式方法,使代码更加简洁
  • 支持从、到或从和到特定值(to:from:)的动画
  • 在单个动画组中按顺序、并行或错开动画多个对象
  • 使用时间线进行高级动画,能够插入间隔、回调等
  • 支持对自定义对象上的任何 NSObject 属性或任何可缓动的值进行动画处理

路线图

  • 改进和清理 API
  • 支持沿 UIBezierPath 动画元素
  • 支持动画 SVG 绘图
  • 支持动画文本和字符

作者

许可

Kinetic 在 MIT 许可下可用。有关更多信息,请参阅 LICENSE 文件。

基本示例

可以通过一行代码对 UIView 或 CALayer 的多个属性进行动画处理

let square = UIView()
square.frame = CGRect(x: 50, y: 50, width: 50, height: 50)
square.backgroundColor = UIColor.redColor()
view.addSubview(square)

// move 250pt to the right and set the height to 100pt for 0.5 seconds
Kinetic.animate(square).to(X(250), Size(height: 100)).duration(0.5).ease(Quartic.easeInOut).play()

或者,您可以使用 Kinetic 提供的扩展,即 tween(),来正确地在 UIView 或 CALayer 实例上设置缓动

square.tween().to(X(250), Size(height: 100)).duration(0.5).ease(Quartic.easeInOut).play()

Basic Tween

在多个对象上动画相同属性同样简单快捷

let greenSquare = UIView()
greenSquare.frame = CGRect(x: 0, y: 50, width: 100, height: 100)
greenSquare.backgroundColor = UIColor (red: 0.0557, green: 0.7144, blue: 0.0677, alpha: 1.0)
view.addSubview(greenSquare)
	
let blueSquare = UIView()
blueSquare.frame = CGRect(x: 0, y: 50, width: 100, height: 100)
blueSquare.backgroundColor = UIColor (red: 0.0, green: 0.6126, blue: 0.9743, alpha: 1.0)
view.addSubview(blueSquare)
	
let orangeSquare = UIView()
orangeSquare.frame = CGRect(x: 0, y: 160, width: 100, height: 100)
orangeSquare.backgroundColor = .orange
view.addSubview(orangeSquare)
	
let timeline = Kinetic.animateAll([greenSquare, blueSquare, orangeSquare]).to(Rotation(y: CGFloat(Double.pi / 2))).duration(1)
timeline.ease(Sine.easeInOut).perspective(1 / -1000).yoyo().repeatCount(3)
timeline.anchor(.center)
timeline.play()

与上面单独的补间目标类似,您可以在一个数组上的Tweenable对象使用tween()方法,这将设置一个补间,但会返回一个Timeline实例

let timeline = [greenSquare, blueSquare, orangeSquare].tween().to(Rotation(y: CGFloat(Double.pi / 2))).duration(1)

Grouped Tween

查看示例项目,以获取使用Kinetic进行更深入和复杂动画的示例。

可动画属性

Kinetic已内置对动画大多数视图和CALayer可见属性的自动支持,但您还可以动画任何自定义的NSObject键值属性

位置

属性 描述
Position(_ position: CGPoint) 使用指定的CGPoint值对目标的起点/位置进行动画
Position(_ x: CGFloat, _ y: CGFloat) 使用指定的xy值对目标的起点/位置进行动画
X(x: CGFloat) 动画目标的origin.xposition.x
Y(y: CGFloat) 动画目标的origin.yposition.y
Center(_ center: CGPoint) 使用指定的CGPoint值对目标的中心位置进行动画
Center(_ x:CGFloat, _ y: CGFloat) 使用指定的xy值对目标的中心位置进行动画
Center(x: CGFloat) 动画目标的center.x
Center(y: CGFloat) 动画目标的center.y
Shift(_ offset: CGPoint) 将当前边界案的起点平移指定的x和y值,作为距离(类似于平移,但更改对象的起点值而不是使用transform)。
Shift(_ x: CGFloat, _ y: CGFloat) 将当前边形案的起点平移指定的x和y距离(类似于平移,但更改对象的起点值而不是使用transform)。
Shift(x: CGFloat) 将目标相对于其当前位置的origin.x位置沿指定距离移动。负值将向左移动目标。
Shift(y: CGFloat) 将目标相对于其当前位置的origin.y位置沿指定距离移动。负值将向上移动目标。

大小

属性 描述
Size(_ size: CGSize) 使用指定的CGSize值对目标的大小进行动画
Size(_ width: CGFloat, _ height: CGFloat) 使用指定的widthheight值对目标的大小进行动画
Size(width: CGFloat) 动画目标的size.width
Size(height: CGFloat) 动画目标的size.height

变换

属性 描述
Translation(_ offset: CGPoint) 通过指定点的x和y值作为距离,使用层的transform属性来移动层的位置
Translation(_ x: CGFloat, _ y: CGFloat) 使用层的transform属性通过特定的x和y距离移动层的位置
Scale(_ value: CGFloat) 将指定的缩放值应用于所有3个轴,以动画化目标对象的缩放
Scale(x: CGFloat, y: CGFloat, z: CGFloat) 使用针对每个轴的特定缩放值来动画化目标对象的缩放
Rotation(_ value: CGFloat) 在z轴上对对象进行二维旋转,以指定的角度动画化对象
Rotation(x: CGFloat) 将对象沿x轴(对于三维旋转)旋转到指定角度的动画
Rotation(y: CGFloat) 将对象沿y轴(对于三维旋转)旋转到指定角度的动画

颜色

属性 描述
BackgroundColor(_ color: UIColor) 动画化视图或层的背景颜色到指定的颜色值
BorderColor(_ color: UIColor) 动画化视图或层的边框颜色到指定的颜色值
FillColor(_ color: UIColor) 动画化视图或层的填充颜色到指定的颜色值,通常用于CAShapeLayer实例
StrokeColor(_ color: UIColor) 动画化视图或层的描边颜色到指定的颜色值,通常用于CAShapeLayer实例

路径

属性 描述
Path(_ path: Path) 动画化目标沿指定路径的进度
StrokeStart(_ value: CGFloat) 动画化路径的起始位置
StrokeEnd(_ value: CGFloat) 动画化路径的结束位置

其他

属性 描述
Frame(_ value)
Alpha(_ value: CGFloat) 动画化对象的透明度到指定的值(从 01.0
CornerRadius(_ value: CGFloat) 动画化视图或层的圆角到指定的值
KeyPath(_ key: String, _ value: Interpolatable) 对NSObject实例上的指定key path的定制属性进行动画处理。value必须是有效的Interpolatable类型。

您提供的动画属性使用类似Swift的语法,您可以通过指定参数来指定要动画化的属性的起始或结束值。例如,要将视图的origin.x从当前位置动画到100.0,您将使用X(100)。但是,如果只是想将视图从当前位置向右移动100pt,则应使用Shift(x: 100),它只规定了沿x轴移动视图的距离。

以下是在库中使用的主要类及其作用

描述
Kinetic 中心类,提供创建补间、时间轴以及从目标中移除它们的便捷静态方法。
Tween 用于对一个或多个可动画化属性的单个Tweenable目标执行动画的主力类。
Timeline 用于将多个补间组合成一个单一的组,支持控制单个补间相对于整体动画持续时间的位置。
动画 是 Tween 和 Timeline 的基类,提供了核心动画功能。与像 Tween 和 Timeline 这样的特定或一系列的Tweenable目标无关,因此在动画期间不会自动执行任何值更新。
Easing 动画的常见缓动属性。
Spring 基于物理动画的基础弹簧。

可插值值

每个补间实例背后都是一系列遵循Interpolatable协议的值,这得到了UIKit中大多数常用值类型的采用(例如CGFloatCGPointUIColor等)。如果只需对属性值执行基于值的基本插值,则可以使用Interpolator实例而不是功能齐全的Tween和/或Timeline类。如果您有一个不是UIViewCALayer的子类的自定义对象,并且无法使用KeyPath属性,因为该对象不是NSObject的子类,这将很有用。

例如,如果您只想使用Kinetic提供的特定计时函数,将100.0的值插值到500.0,则只需在起始值上使用interpolator(to:duration:function:apply:)方法即可。

(100.0.interpolator(to: 500.0, duration: 1.0, function: Easing.type(Quadratic.easeInOut)) { (value) in
	print("\(value)")
}).run()

当直接使用插值器时,您需要负责更新相应的实例上的值。此外,此方法不支持TweenTimeline中可用的任何功能。

控制补间

使用 Kinetic.animate: 或 Timeline 使用 Kinetic.animateAll: 创建 Tween 实例后,在播放过程中控制动画变得非常简单。

您可以在播放之前配置您的 Tween,以定义它的延迟、缓动或弹簧、重复次数或无限重复

// sets the initial state of the animation before playback, where `...` is a series of `Property` instances
tween.from(...)

// sets the final state of the animation when playback completes, where `...` is a series of `Property` instances
tween.to(...)

// total duration of the animation, in seconds, not including any delay value
tween.duration(0.5)

// wait 2 seconds before starting the animation
tween.delay(2)

// set the easing to use for the animation, which will be used for all properties in the tween
tween.ease(Quartic.easeInOut)

// configure the tween to use a spring animation, which will be used instead of any easing previously set
tween.spring(tension: 100, friction: 12)

// tell the tween to repeat 4 additional times, meaning it will play a total of 5 times
tween.repeatCount(4)

// set a delay of 0.5 seconds between repeats
tween.repeatDelay(0.5)

// tell the tween to repeat forever until stopped using stop() or pause()
tween.forever()

// reverses the direction of playback each time the tween is repeated
// if the tween is configured to repeat 4 times, then the animation will play with the pattern: forward, reversed, forward, reversed, forward.
tween.yoyo()

// set the transform perspective for the tween's associated object
// this is only used for three-dimensional CALayer transformation
tween.perspective(1 / -1000)

一旦您配置了 Tween 并使用 play() 方法开始播放,您随时可以停止、暂停、恢复、定位、反转或重新开始一个 Tween

// plays the tween from the beginning
tween.play()

// stops the tween at the current position
tween.pause()

// resumes playback from the tween's current position
tween.resume()

// reverses playback direction toward the beginning
tween.reverse()

// returns playback direction to the normal direction
tween.forward()

// restarts the tween from the beginning
tween.restart()

// jump to 0.5 seconds into the tween
tween.seek(0.5)

// immediately stop and remove the tween from the object
tween.kill()

// get the current progress of the tween from 0 (start) to 1 (end); doesn't account for repeats (a single animation cycle)
tween.progress()

// move the animation's playhead progress from 0 (start) to 1 (end) excluding repeats and repeatDelays (a single animation cycle)
tween.setProgress(progress: Float)

// get the current progress of the tween from 0 (start) to 1 (end) including repeats and repeatDelays
tween.totalProgress()

// move the animation's playhead progress from 0 (start) to 1 (end) including repeats and repeatDelays
tween.setTotalProgress(progress: Float)

// get the total elapsed time of the tween including any repeats and delays
tween.time()

您还可以通过中央 Kinetic 模块提供的便捷方法删除单个对象的多个 Tween

Kinetic.killTweensOf(square)

要从所有对象中删除当前正在运行的所有 Tween,只需调用 killAll()

Kinetic.killAll(greenSquare)

杀死和删除一个 Tween 类似于 pause(),将在当前位置停止动画,而不会将关联的对象返回到其原始起始位置。该 Tween 也将与对象解关联,并从 Tween 缓存中删除。

回调函数

您可以为 Tween 播放期间的多个事件分配回调块,包括开始时、更新对象的属性时、重复时以及完成时。将作为参数传递给您的块的 Tween 实例。

Animation 实例将触发以下事件

// called when the tween starts animating
tween.on(.started) { (tween) -> Void in
	print("tween started")
}

// called when the tween's properties are updated during the animation
tween.on(.updated) { (tween) -> Void in
	print("tween updated: time=\(tween.elapsed)")
}

// called each time the tween repeats
// if the tween's playback is reversed, this will be called when the tween's position reaches the beginning
// of the tween, or 0, instead of the end
tween.on(.repeated) { (tween) -> Void in
	print("tween repeated")
}

// called when the animation is cancelled before it completes
tween.on(.cancelled) { (tween) -> Void in
	print("tween cancelled")
}

// called when all properties of the tween have finished animating to their final values
tween.on(.completed) { (tween) -> Void in
	print("tween completed")
}

自定义属性

您大多数时候都在对 UIView 和 CALayer 实例及其视觉属性进行动画处理。但是,您可能还需要对不支持 Kinetic 标准属性集或项目中自定义对象的属性进行动画处理。您可以使用 Tween 和符合 KeyPathTweenable 协议的 custom NSObject 子类的 KeyPath(_ key: String, _ value: Interpolatable) 属性来完成此操作

class CountingObject: NSObject, KeyPathTweenable {
	var value: Float = 0
}

这一用法的一个好实例是为 UILabel 设置一个动画,例如从 50 到 250 的值变化。使用 Tween 实例和 KeyPath() 属性,这和其他动画一样简单

let textLabel = UILabel()
textLabel.font = UIFont.systemFont(ofSize: 40)
textLabel.textColor = UIColor.black
textLabel.frame = CGRect(x: 50, y: 50, width: 200, height: 50)
view.addSubview(textLabel)
	
let testObject = CountingObject()
testObject.value = 50
textLabel.text = "\(testObject.value)"
		
let tween = testObject.tween()
    .to(KeyPath("value", 250.0))
    .duration(2)
    .ease(Exponential.easeOut)
	
tween.on(.updated) { (animation) in
	self.textLabel.text = "\(String(format:"%.1f", self.testObject.value))"
}.on(.completed) { (animation) in
	print("DONE")
}

Counting Label

只要自定义属性属于符合 KeyPathTweenable 的 NSObject 子类,并且具有数值属性,就可以使用任何自定义属性。

除了上面的 可插值值 部分中解释的直接使用插值器之外,可以使用 KeyPath() 属性方法为自定义属性动画提供替代方案。

时间轴

动力时间轴让您可以将多个缓动实例组合成一个单独、易于控制的序列,对复杂动画进行精确的时间管理。不使用时间轴实例,您需要创建多个缓动实例,并手动计算它们的延迟值,以创建您想要的精确序列。

串联动画

在许多情况下,您可能想要对单个或多个对象进行串联或顺序动画,其中每个缓动实例依次执行。例如,如果您想要将视图向右移动,然后向下移动,再将其放大2倍,持续3秒钟,您可以通过创建三个缓动实例,并使它们的延迟值相差1秒来实现。

square.tween()
    .to(X(110))
    .duration(1)
    .ease(Cubic.easeInOut)
    .play()
	
square.tween()
    .to(Y(250))
    .duration(1)
    .ease(Cubic.easeInOut)
    .delay(1)
    .play()
	
square.tween()
    .to(Scale(2))
    .duration(1)
    .ease(Cubic.easeInOut)
    .delay(2)
    .play()

请注意,如果更改任何一个单个缓动实例的持续时间,您还必须确保调整序列的延迟值。尝试暂停、重新启动或反转序列更具挑战性。然而,通过使用时间轴实例,您可以轻松执行所有这些功能。

let timeline = Timeline()
timeline.add(square.tween().to(X(110)).duration(1).ease(Cubic.easeInOut))
timeline.add(square.tween().to(Y(250)).duration(1).ease(Cubic.easeInOut))
timeline.add(square.tween().to(Scale(2)).duration(1).ease(Cubic.easeInOut))
timeline.play()

Timeline Sequence

上述时间轴将按顺序执行每个缓动实例,总持续时间为3秒,因为每个缓动实例的长度为1秒。

除了让每个缓动实例依次播放,您还可以为您的序列中的单一或所有缓动实例指定一个位置。例如,我们希望在时间轴上1.5秒的位置播放上述序列中的第二个缓动实例,而不是在第一个缓动实例完成后立即播放。

let timeline = Timeline()
timeline.add(square.tween().to(X(110)).duration(1).ease(Cubic.easeInOut))
timeline.add(square.tween().to(Y(250)).duration(1).ease(Cubic.easeInOut), position: 1.5)
timeline.add(square.tween().to(Scale(2)).duration(1).ease(Cubic.easeInOut))
timeline.play()

此更改将使第二个缓动实例在动画1.5秒时播放,然后在它完成后立即播放最后一个缓动实例,时间为2.5秒。因此,我们时间轴的新总持续时间将是3.5秒,而不是3秒。

Timeline Sequence

###组合 + 分步动画###

使用Kinetic.animateAll,您可以使用一行代码对多个对象的相同属性进行动画处理。例如,您有3个方形视图,您想要同时将其缩放并旋转45度。

let squares = [greenSquare, blueSquare, redSquare]
let timeline = squares.tween()
                    .to(Scale(2), Rotation(CGFloat(Math.pi / 2.0)))
                    .duration(1)
                    .ease(Sine.easeInOut)
timeline.play()

Timeline Grouped

使用时间轴还提供了一种对多个动画进行分步动画的能力。例如,您可能有一个由水平条组成的列,您想要将它们的宽度动画化到最终状态。您可以使用基本的时间轴实例,相对开始时间逐渐偏移它们的定位,但使用stagger:在您的Timeline实例上有更简单的方法。

let squares = [greenSquare, blueSquare, redSquare]
let timeline = squares.tween()
                    .to(Size(width: 250))
                    .duration(1)
                    .stagger(0.08)
                    .spring(tension: 100, friction: 12)
timeline.play()

在一行代码中,您可以使用弹簧动画每个位于squares中的项目,从起始宽度到200的宽度,每个偏移0.08秒。

Timeline Staggered

Kinetic.animateAll:方法将返回时间轴的实例。

您还可以为时间轴添加标签,用于在添加其他缓动实例或回放时进行引用。例如,您可能希望在时间轴中为视图添加一个颜色变化动画,并让其他缓动实例相对于该位置执行。首先在您想要引用的时间创建一个标签,然后根据该标签添加或偏移缓动实例。

let resize = square.tween()
                .to(Size(150,100))
                .duration(1)
                .ease(Cubic.easeInOut)
					
let color = square.tween()
                .to(BackgroundColor(UIColor.blue))
                .duration(0.75)

timeline.addLabel("colorChange", position: 1.3)
timeline.add(color, relativeToLabel: "colorChange", offset: 0)
timeline.add(resize, relativeToLabel: "colorChange", offset: 0.5)

###时间标签###

您可以在时间轴中添加任意数量的时间标签,然后用作沿着时间轴的特定位置的参考点。一旦设置了一个标签,您就可以使用偏移值相对于该特定标签添加时间轴的缓动。负偏移值将在标签之前插入相应数量的秒的缓动。

// use a label to store a position reference when the color change still start animating
timeline.addLabel("colorChange", position: 1.3)

// add the color change tween to the timeline relative to our "colorChange" label
let color = square.tween().to(BackgroundColor(UIColor.blue)).duration(0.75)
timeline.add(color, relativeToLabel: "colorChange", offset: 0)

// resize the view 1 second after the color change starts
let resize = square.tween().to(Size(150,100)).duration(1).ease(Cubic.easeInOut)
timeline.add(resize, relativeToLabel: "colorChange", offset: 0.5)

// move the view 0.25 seconds before the color change starts
let move = square.tween().to(Position(200,200)).duration(1).ease(Cubic.easeInOut)
timeline.add(move, relativeToLabel: "colorChange", offset: -0.25)

timeline.play()

Timeline Labels

###时间回调##

使用时间线,您还可以在任何时间插入回调块,只要在时间线的总持续时间内即可,这如果在时间线播放时执行某些操作或执行另一动画,则非常有用。

timeline.addCallback(Float(idx) * 0.15 + 1.5, block: {
	dot.tween().to(FillColor(UIColor.orange).duration(0.5).play()
})

Timeline Callbacks

###控制时间线###

时间线支持与补间(tween)相同的控件方法,如 pause()stop()resume()restart()seek()。然而,时间线还提供了一些额外的方法,因为它们支持在特定时间插入标签。您可以使用 goToAndPlay() 和 `goToAndStop()` 在先前设定的特定标签处停止或从此标签开始播放。

timeline.addLabel("colorChange", 0.7)
timeline.play()
...
timeline.goToAndStop("colorChange")

如果指定标签在时间线上不存在,则时间线将从或开始于时间线的开头。

时间线也支持与补间相同的回调块,因此您可以将 onStart()onUpdate()onRepeat()onComplete() 用于时间线实例。如果需要通知特定补间何时开始或完成,您还可以在父时间线回调的基础上,对时间线内的单个补间实例有额外的回调。

有关使用时间线的详细示例,请参阅示例项目。