Reputation: 3833
I'm currently animating one of my constraints in an animation block, however I wish to customise the animation type - further to that given by the preset UIVIewAnimationOptions:
UIView.animateWithDuration(2.0, delay: 0.3, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
self.heightTransition.constant = self.view.bounds.height - 52
self.view.layoutIfNeeded()
}, completion: { (complete) -> Void in
})
I've looked into the potential of using a CAMediaTimingFunction, as shown here (http://cubic-bezier.com/#.44,.94,.79,-0.01), where you can pass in values to alter the animation style.
My question then is, how can I apply the use of CAMediaTimingFunction upon animating UIView constraints?
Upvotes: 4
Views: 600
Reputation: 35
I don't know if it's possible to do it directly, because NSLayoutConstraint is part of the UIKit, while CALayer is part of the Core Animation. But for me works this approach, where i do my CABasicAnimation with custom cubic bezier animation curve, then on completion UIView returns to it's starting position defined by it's constraints before animation started(or i can set other constraints to my UIView in animation completion block.), you can paste this in empty new project if you want to play around:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
super.view.backgroundColor = .white
//Button to trigger animation.
let button: UIButton = {
let button = UIButton()
super.view.addSubview(button)
button.setTitleColor(UIColor.systemCyan, for: .normal)
button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
button.setTitle("Animate!", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.topAnchor.constraint(equalTo: super.view.topAnchor, constant: super.view.frame.height * 0.886),
button.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
button.heightAnchor.constraint(equalToConstant: super.view.frame.height * 0.024),
])
return button
}()
}
@objc func buttonPressed() {
//Remove view created previous button press.
for view in super.view.subviews {
if view.backgroundColor == .systemMint {
view.removeFromSuperview()
}
}
//heightConstraint is distance we want to walk from start to finish of animation.
var heightConstraint: NSLayoutConstraint!
var topConstraint: NSLayoutConstraint!
let view: UIView = {
let view = UIView()
super.view.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.masksToBounds = true
view.backgroundColor = .systemMint
//After animation completion view will return to this constraints.
heightConstraint = view.heightAnchor.constraint(equalToConstant: super.view.frame.height * 0.605)
topConstraint = view.topAnchor.constraint(equalTo: super.view.topAnchor, constant: -600)
NSLayoutConstraint.activate([
topConstraint,
view.widthAnchor.constraint(equalToConstant: super.view.frame.width * 0.87),
heightConstraint,
view.centerXAnchor.constraint(equalTo: super.view.centerXAnchor)
])
view.layer.cornerRadius = super.view.frame.height * 0.0495
return view
}()
//Create custom animation curve based on cubic bezier controlPoints
let timingFunction = CAMediaTimingFunction(controlPoints: 0,1.07,0.15,0.97 /*0,1,0,1*/)
//We can't animate our topConstraint directly, so we'll use "position.y"
let animation = CABasicAnimation(keyPath: "position.y")
animation.duration = 3
//position.y counted from midY, so we have to subtract half of view's height
//so view's bottom == superview's top is our starting point
animation.fromValue = -heightConstraint.constant/2
//and so with finish point
animation.toValue = heightConstraint.constant/2
animation.timingFunction = timingFunction
animation.fillMode = .forwards
animation.isRemovedOnCompletion = true
CATransaction.setCompletionBlock({
/*Here set necessary constraints manually,
on completion the will be applied.
(Early we set this constraint to -600, so when animation
finished - our UIView returns to it's position
before animation started, preserving constraints.
We can set it to 0 here, or we could do it earlier
instead of -600, depends of what we need.)*/
topConstraint.constant = 0
})
view.layer.add(animation, forKey: nil)
}
}
As we can see in gif, constraints set to UIView preserved after animation completion.
Upvotes: 1