The effect could be implemented like the following code in animateTransition
method:
UIView.animateWithDuration(duration,
delay: 0,
usingSpringWithDamping: 0.3,
initialSpringVelocity: 0.0,
options: .CurveLinear,
animations: {
fromVC.view.alpha = 0.5
toVC.view.frame = finalFrame
},
completion: {_ -> () in
fromVC.view.alpha = 1.0
transitionContext.completeTransition(true)
})
But how could I implement it using gravity and collision behaviors(UIGravityBehavior
, UICollisionBehavior
)?
And a more general question may be "How to use the UIDynamicAnimator
to customize the transitions between UIViewControllers
?"
You can find the solution under the post Custom view controller transitions with UIDynamic behaviors by dasdom.
And the Swift code:
func transitionDuration(transitionContext: UIViewControllerContextTransitioning!) -> NSTimeInterval {
return 1.0
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning!) {
// 1. Prepare for the required components
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
let finalFrame = transitionContext.finalFrameForViewController(toVC)
let containerView = transitionContext.containerView()
let screenBounds = UIScreen.mainScreen().bounds
// 2. Make toVC at the top of the screen
toVC.view.frame = CGRectOffset(finalFrame, 0, -1.0 * CGRectGetHeight(screenBounds))
containerView.addSubview(toVC.view)
// 3. Set the dynamic animators used by the view controller presentation
var animator: UIDynamicAnimator? = UIDynamicAnimator(referenceView: containerView)
let gravity = UIGravityBehavior(items: [toVC.view])
gravity.magnitude = 10
let collision = UICollisionBehavior(items: [toVC.view])
collision.addBoundaryWithIdentifier("GravityBoundary",
fromPoint: CGPoint(x: 0, y: screenBounds.height),
toPoint: CGPoint(x: screenBounds.width, y: screenBounds.height))
let animatorItem = UIDynamicItemBehavior(items: [toVC.view])
animatorItem.elasticity = 0.5
animator!.addBehavior(gravity)
animator!.addBehavior(collision)
animator!.addBehavior(animatorItem)
// 4. Complete the transition after the time of the duration
let nsecs = transitionDuration(transitionContext) * Double(NSEC_PER_SEC)
let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(nsecs))
dispatch_after(delay, dispatch_get_main_queue()) {
animator = nil
transitionContext.completeTransition(true)
}
}
A little more complicated than using animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:
method.
EDIT: Fixed a bug when 'transitionDuration' is ≤1