The creation of interactive animations, as well as the interruptible animations in iOS 10 required new additional APIs. The major class is the open class UIViewPropertyAnimator : NSObject, UIViewImplicitlyAnimating, NSCopying.
Animator Creation and Animation Start Example
// setting up the timing parameters:
let timing = UICubicTimingParameters(animationCurve: .easeInOut)
// creating the animator with the duration and timing parameters:
let animator = UIViewPropertyAnimator(duration: 3.0, timingParameters:timing)
// adding the animation block
animator.addAnimations {
self.animatedView.center = CGPoint(x: 400, y: self.animatedView.center.y)
}
// adding the Completion block that is executed after the animation completion:
animator.addCompletion {_ in
self.animatedView.backgroundColor = UIColor.red()
}
// starting the animator
animator.startAnimation()
The UIViewPropertyAnimator Class
The new UIViewPropertyAnimator
class is fairly simple, casual and interruptible. The animations can be scrolled to any position and also played backwards. Due to this class, the animations become smoother and more natural.
UIViewPropertyAnimator
supports 2 protocols:
public protocol UIViewAnimating : NSObjectProtocol
public protocol UIViewImplicitlyAnimating
Important Observable Properties
animator.startAnimation () : |
active |
true |
false |
animator.pauseAnimation (): |
active |
false |
false |
animator.isReversed = true : |
active |
false |
true |
animator.startAnimation () : |
active |
true |
true |
animator.stopAnimation (false*) |
stopped |
* the false parameter means the animation will be stopped but with no ending:
stopAnimation(_ withoutFinishing: Bool)?
. If the value is true, the state is inactive.
animator.finishAnimation (.current)
.end, .start, .current.
finishAnimation(at finalPosition: UIViewAnimatingPosition) finishes the animation on a certain position:
All the described manipulations are present on the state change chart below:
To stop the animation, you can use TapRecognizer
and depending on the state, perform actions:
switch animator.state {
case .active:
if animator.isRunning {
progressAnimator.pauseAnimation();
animator.pauseAnimation();
} else {
animator.startAnimation()
progressAnimator.startAnimation()
} default:
break
} }
To fast forward the progress, you can use UIPanGestureRecognizer
and set the animator’s fractionComplete parameter:
func handleProgress (_ gr : UIPanGestureRecognizer) {
let s = gr.location(in: progress)
let f = min(s.x / progress.bounds.size.width, 1.0)
let fraction = max(0.0, f)
animator.fractionComplete = fraction
progressAnimator.fractionComplete = fraction
}
Time Curve
By default, Apple has four standard curves – easeOut, easeIn, easeInOut, linear.
You can enhance the animation with the help of the following classes:
UICubicTimingParameters
– allows building the animation based on the two control points:
let controlPoint1 = CGPoint(x: 0.2, y: 0.1)
let controlPoint2 = CGPoint(x: 0.8, y: 0.8)
let parameters = UICubicTimingParameters(controlPoint1: controlPoint1, controlPoint2: controlPoint2)
animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: parameters)
UISpringTimingParameters
– adds springiness to the animation behavior with the help of various parameters like:
let mass: CGFloat = 2.0 // weight
let stiffness: CGFloat = 15.0 //elasticity
let damping: CGFloat = ...// point where the system comes to rest in the shortest period of time
let underDamping: CGFloat = damping * 0.5
let initialVelocity: CGVector = CGVector.zero
let springParameters: UISpringTimingParameters = UISpringTimingParameters(mass: mass, stiffness: stiffness, damping: underDamping, initialVelocity: initialVelocity)
let customSpringParameters = UIViewPropertyAnimator(duration: 2.0, timingParameters: springParameters)
customSpringParameters.addAnimations {
// animation block}
Using the springParameters
in this case means that the duration
value is ignored.
Interruptible Keyframe Animations
Setting up the interruptible frame animation:
animator.addAnimations { _ in
UIView.animateKeyframes(withDuration: self.duration, delay: 0.0, options:[.calculationModeCubic]
{_ in
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25) {
self.squareView1.center = CGPoint(x: 50.0, y: 300.0)
}
UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25) {
self.squareView1.center = CGPoint(x: 100.0, y: 100.0)
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) {
self.squareView1.center = CGPoint(x: 200.0, y: 300.0)
}
UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
self.squareView1.center = CGPoint(x: 500.0, y: 400.0)
}
} }
These APIs as well as the UIViewPropertyAnimator
class were supposed to seriously boost the performance of apps with animations and smoothen the experience.
After a lot of testing and implementation done to some of the apps we worked on, these statement is totally proven. The fine tuned parameters and the predictive UI animations significantly improve the way animation is perceived in iOS.