UIViewPropertyAnimator
A class that animates changes to views and allows the dynamic modification of those animations.
UIViewPropertyAnimator是iOS10引入的新类,使用该类可以动态的修改views的动画
属性
@available(iOS 10.0, *)
open class UIViewPropertyAnimator : NSObject, UIViewImplicitlyAnimating, NSCopying {
// 动画曲线
@NSCopying open var timingParameters: UITimingCurveProvider? { get }
// 动画时间
open var duration: TimeInterval { get }
// 默认为0,延时时间
open var delay: TimeInterval { get }
/// 默认 YES. 是否允许交互
open var isUserInteractionEnabled: Bool
}
方法
- 初始化方法(Initializing a Property Animator)
// 使用自定义动画曲线对象初始化Property Animator
public init(duration: TimeInterval,
timingParameters parameters: UITimingCurveProvider)
/// 便捷构造方法
// 普通曲线动画方式
public convenience init(duration: TimeInterval,
curve: UIView.AnimationCurve,
animations: (() -> Void)? = nil)
// 定义贝塞尔动画曲线
public convenience init(duration: TimeInterval,
controlPoint1 point1: CGPoint,
controlPoint2 point2: CGPoint,
animations: (() -> Void)? = nil)
// 弹黄效果
public convenience init(duration: TimeInterval,
dampingRatio ratio: CGFloat,
animations: (() -> Void)? = nil)
// 该方法跟UIView的动画方法类似,根据需求填写参数
open class func runningPropertyAnimator(withDuration duration: TimeInterval,
delay: TimeInterval,
options: UIView.AnimationOptions = [],
animations: @escaping () -> Void,
completion: ((UIViewAnimatingPosition) -> Void)? = nil) -> Self
- UIViewImplicitlyAnimating
public protocol UIViewImplicitlyAnimating : UIViewAnimating {
// 添加具体的动画闭包带延时
optional public func addAnimations(_ animation: @escaping () -> Void, delayFactor: CGFloat)
// 添加具体的动画闭包
optional public func addAnimations(_ animation: @escaping () -> Void)
@available(iOS 10.0, *) // 添加完成闭包
optional public func addCompletion(_ completion: @escaping (UIViewAnimatingPosition) -> Void)
optional public func continueAnimation(withTimingParameters parameters: UITimingCurveProvider?,
durationFactor: CGFloat)
}
- UIViewAnimating
public protocol UIViewAnimating : NSObjectProtocol {
@available(iOS 10.0, *)
public var state: UIViewAnimatingState { get }
// 动画是否正在运行
public var isRunning: Bool { get }
// 反转动画
public var isReversed: Bool { get set }
// 0-1,执行的进度
public var fractionComplete: CGFloat { get set }
// 开始动画
public func startAnimation()
// 指定延时之后开始动画
public func startAnimation(afterDelay delay: TimeInterval)
// 暂停动画
public func pauseAnimation()
// 停止动画,参数为true将变为inactive状态,否则是stopped状态
public func stopAnimation(_ withoutFinishing: Bool)
// 处于stopped状态被调用
@available(iOS 10.0, *)
public func finishAnimation(at finalPosition: UIViewAnimatingPosition)
}
- UIViewAnimatingState(动画状态)
animation_states_2x_6526d868-7211-4cbd-b7e1-aadfb0127310.png
@available(iOS 10.0, *)
public enum UIViewAnimatingState : Int {
case inactive // The animation is not executing.
case active // The animation is executing.
case stopped // The animation has been stopped and has not transitioned to inactive.
}
当动画开始或者暂停的时候,动画状态为
active
当控件被创建出来且没有开始执行动画或者已经执行完动画的时候,它的状态是
inactive
。当动画执行完毕或者使用
stop
命令暂停动画后,控件的状态变为stopped
UIViewAnimatingPosition(动画位置)
@available(iOS 10.0, *)
public enum UIViewAnimatingPosition : Int {
case end
case start
case current
}
实战
体验初始化方法
- 常用动画方式
func moveAnimation(_ point: CGPoint) {
let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeInOut) {
self.redView.center = point
}
animator.startAnimation()
}
2018-11-30 16-10-30.2018-11-30 16_10_40.gif
如果想延时动画,使用下面方法
animator.startAnimation(afterDelay: 3.0)
- 弹性动画
func springAnimation(_ point: CGPoint) {
let animator = UIViewPropertyAnimator(duration: 1.0, dampingRatio: 0.4) {
self.redView.center = point
}
animator.startAnimation()
}
2018-11-30 16-12-24.2018-11-30 16_12_35.gif
- 自定义动画曲线
方式一
func customCurveAnimation(_ point: CGPoint) {
let animator = UIViewPropertyAnimator(duration: 1.0,
controlPoint1: CGPoint(x: 0.1, y: 0.5),
controlPoint2: CGPoint(x: 0.5, y: 0.2)) {
self.redView.center = point
}
animator.startAnimation()
}
方式二
func cubicAnimation(_ point: CGPoint) {
let cubicTiming = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.1, y: 0.5),
controlPoint2: CGPoint(x: 0.5, y: 0.2))
let animator = UIViewPropertyAnimator(duration: 1.0, timingParameters: cubicTiming)
animator.addAnimations {
self.redView.center = point
}
animator.startAnimation()
}
2018-11-30 16-14-25.2018-11-30 16_14_54.gif
- 类方法动画
func classAnimator(_ point: CGPoint) {
// 动画立即开始
let animator = UIViewPropertyAnimator
.runningPropertyAnimator(withDuration: 1.0,
delay: 0.0,
options: [],
animations: {
self.redView.center = point },
completion: { position in
print(position) })
}
2018-11-30 16-44-53.2018-11-30 16_45_02.gif
使用该方法创建的动画会立马执行,返回的animator可以根据需求进行设置。动画完成执行闭包,得到动画的最终position,使用该值能够确定动画是在begin, end还是其他位置停止的。
相关功能
- 添加动画
func addAnimations(_ point: CGPoint) {
// 位置
let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeIn) {
self.redView.center = point
}
// 透明度
animator.addAnimations {
self.redView.alpha = 0.2
}
// 缩放
animator.addAnimations {
self.redView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2)
}
animator.startAnimation()
}
2018-11-30 16-21-33.2018-11-30 16_21_43.gif
可以看到动画是同时执行的,因为默认的状态的inactive,所以多个动画闭包同时执行。如果是在动画的过程中添加动画,那么将会在剩余的时间内执行对应的动画
- 添加完成闭包
可以在动画完成之后执行某些结束操作
func addCompletion(_ point: CGPoint) {
let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeIn) {
self.redView.center = point
}
animator.addAnimations {
self.redView.alpha = 0.2
}
animator.addCompletion { position in
switch position {
case .end:
print("Completion handler called at end of animation")
case .current:
print("Completion handler called mid-way through animation")
case .start:
print("Completion handler called at start of animation")
}
}
animator.startAnimation()
}
动画执行结束,打印
Completion handler called at end of animation
- 控制进度
func scrubAnimation() {
let animtor = UIViewPropertyAnimator(duration: 5.0, curve: .easeIn) {
self.redView.frame = CGRect(x: 300, y: 150, width: 100, height: 50)
}
self.animator = animtor
// 添加滑动条
let scrubber = UISlider(frame: CGRect(x: 50, y: 100, width: 300, height: 20))
scrubber.addTarget(self, action: #selector(slideEvent(_:)), for: .valueChanged)
view.addSubview(scrubber)
}
@objc func slideEvent(_ slider: UISlider) {
self.animator.fractionComplete = CGFloat(slider.value)
}
2018-11-30 17-20-40.2018-11-30 17_20_58.gif
- 反转动画
在动画的执行过程中,返回最初的状态
func reverseAnimations(_ point: CGPoint) {
let animator = UIViewPropertyAnimator(duration: 1.0, curve: .easeIn) {
self.redView.center = point
}
self.animator = animator
animator.startAnimation()
}
@objc func buttonClicked() {
self.animator.isReversed = true
}
2018-11-30 17-36-30.2018-11-30 17_36_44.gif
参考
UIViewPropertyAnimator
iOS 10 Day by Day :: Day 4 :: UIViewPropertyAnimator