一个适用于 iOS、tvOS 和 macOS 的动画库,它使用基于物理的动画(包括弹簧动画)来驱动交互,使其移动和响应更加真实自然。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
// Springs animate changes to a value
let spring = Spring(initialValue: view.center)
// The `onChange` closure will be called every time the spring updates
spring.onChange = { [view] newCenter in
view.center = newCenter
}
/// The view's center will realistically animate to the new target value.
spring.target = CGPoint(x: 300, y: 200)
有几种方法可以将 Advance 集成到你的项目中。
手动: 将 Advance.xcodeproj
添加到你的项目中,然后将 Advance-{iOS|macOS|tvOS}.framework
作为“Embedded Binary”(嵌入式二进制)添加到你的应用程序目标中(在目标设置的 General 选项卡下)。完成之后,在你的代码中添加 import Advance
即可。
Carthage: 将 github "timdonnelly/Advance"
添加到你的 Cartfile
文件中。
CocoaPods: 将 pod 'Advance'
添加到你的 Podfile
文件中。
Swift Package Manager: 在你的 Project.swift
文件中添加依赖项:.package(url: "http://github.com/timdonnelly/Advance", from: "3.0.0")
API 文档在此处提供。
Advance 动画在每一帧上应用(在 iOS/tvOS 上使用 CADisplayLink
,在 macOS 上使用 CVDisplayLink
),从而可以在任何时候进行精细的控制。
Spring
实例使用弹簧物理原理,随时间推移动画值的变化。
let spring = Spring(initialValue: 0.0)
spring.onChange = { [view] newAlpha in
view.alpha = newAlpha
}
// Off it goes!
spring.target = 0.5
/// Spring values can be adjusted at any time.
spring.tension = 30.0 /// The strength of the spring
spring.damping = 2.0 /// The resistance (drag) that the spring encounters
spring.threshold = 0.1 /// The maximum delta between the current value and the spring's target (for each component) for which the simulation can enter a converged state.
/// Update the simulation state at any time.
spring.velocity = 6.5
spring.value = 0.2
/// Sets the spring's target and the current simulation value, and removes all velocity. This causes the spring to converge at the given value.
spring.reset(to: 0.5)
Animator
允许在可以执行的动画类型方面有更大的灵活性,但为此牺牲了一些便利性。具体来说,animator 允许为单个值执行任何类型的动画或模拟。
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
/// Animators coordinate animations to drive changes to a value.
let sizeAnimator = Animator(initialValue: view.bounds.size)
sizeAnimator.onChange = { [view] newSize in
view.bounds.size = newSize
}
/// A simple timed animation
sizeAnimator.animate(to: CGSize(width: 123, height: 456), duration: 0.25, timingFunction: .easeInOut)
/// Some time in the future (before the previous timed animation was complete)...
/// Spring physics will move the view's size to the new value, maintaining the velocity from the timed animation.
sizeAnimator.simulate(using: SpringFunction(target: CGSize(width: 300, height: 300)))
/// Some time in the future (before the previous spring animation was complete)...
/// The value will keep the same velocity that it had from the preceeding spring
/// animation, and a decay function will slowly bring movement to a stop.
sizeAnimator.simulate(using: DecayFunction(drag: 2.0))
Animator 支持两种根本不同的动画类型:定时动画和模拟动画。
定时动画,顾名思义,是定时的:它们有一个固定的持续时间,并以可预测的方式动画到最终值。
animator.animate(to: CGSize(width: 123, height: 456), duration: 0.25, timingFunction: .easeInOut)
TimingFunction
描述了定时动画的节奏。
TimingFunction
附带一组标准函数。
TimingFunction.linear // No easing
TimingFunction.easeIn
TimingFunction.easeOut
TimingFunction.easeInOut
TimingFunction.swiftOut // Similar to Material Design's default curve
自定义 timing 函数可以表示为单位贝塞尔曲线(此处描述)。
let customTimingFunction = TimingFunction(x1: 0.1, y1: 0.2, x2: 0.6, y2: 0.0)
模拟动画使用模拟函数来驱动基于物理的过渡效果。模拟函数是符合 SimulationFunction
协议的类型。
模拟动画可以使用两种不同的方法启动。
// Begins animating with the custom simulation function, maintaining the previous velocity of the animator.
animator.simulate(using: MyCustomFunction())
// or...
// Begins animating with the custom simulation function, imparting the specified velocity into the simulation.
animator.simulate(using: DecayFunction(), initialVelocity: dragGestureRecognizer.velocity(in: view))
符合 VectorConvertible
协议的值可以通过 Advance 进行动画处理。符合的类型可以转换为 Vector
实现,也可以从 Vector
实现转换而来。
public protocol VectorConvertible: Equatable, Interpolatable {
associatedtype VectorType: SIMD where VectorType.Scalar == Double
init(vector: VectorType)
var vector: VectorType { get }
}
该库通过扩展为许多常见类型添加了符合性。
如果你遇到任何问题或意外情况,请提交 issue。
对于建议或新功能,请考虑提交包含功能实现的 PR。如果你不确定如何实现更改,可以使用 issue,但通常情况下,可运行的代码更容易评估。
本项目根据 BSD 2-clause 许可证发布。