20210716, found some online exit animation, run, a face meng
This article discusses, how to solve
Entrance animation, very simple
-
Specifies the animation time, through the func transitionDuration (using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
-
How to animation, through the func animateTransition (using transitionContext: UIViewControllerContextTransitioning)
Left hand from View Controller, previous Controller,
One on the right, to View Controller, the next Controller,
Let the last one disappear, let the next one appear
Uiview. animate Adjusts the animation properties,
Basically, I’m going to change the view frame, and that’s it
The following code, the effect is relatively simple
You present a controller, from the bottom up,
You can do it here, up, down, left, right, you can push out the controller
enum PresentingDirection{ case top, right, left, bottom var bounds: CGRect{ UIScreen.main.bounds } func offsetF(withFrame viewFrame: CGRect) -> CGRect{ let h = bounds.size.height let w = bounds.size.width switch self { case .top: return viewFrame.offsetBy(dx: 0, dy: -h) case .bottom: return viewFrame.offsetBy(dx: 0, dy: h) case .left: return viewFrame.offsetBy(dx: -w, dy: 0) case .right: return viewFrame.offsetBy(dx: w, dy: 0) } } } class CustomPresentationController: NSObject, UIViewControllerAnimatedTransitioning{ fileprivate var presentingDirection: PresentingDirection init(direction orientation: PresentingDirection) { presentingDirection = orientation } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 1 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from), let toCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) else{ return } let finalCtrlFrame = transitionContext.finalFrame(for: toCtrl) let containerView = transitionContext.containerView toCtrl.view.frame = presentingDirection.offsetF(withFrame: finalCtrlFrame) containerView.addSubview(toCtrl.view) UIView.animate(withDuration: transitionDuration(using: TransitionContext), Delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .curvelinear) {fromctrl.view.alpha = 0.5 toCtrl.view.frame = finalCtrlFrame} completion: { _ in fromCtrl.view.alpha = 1 transitionContext.completeTransition(true) } } }Copy the code
Appearance animation, updated
Follow the example above
1. Make do
The familiar recipe, again, gets rid of both methods,
One is animation time, one is how animation
class CustomDismissController: NSObject, UIViewControllerAnimatedTransitioning{ fileprivate var presentingDirection: PresentingDirection init(direction orientation: PresentingDirection) { presentingDirection = orientation } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 1 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from), let toCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to), let toView = toCtrl.view else{ return } let finalCtrlFrame = transitionContext.finalFrame(for: FromCtrl) let containerView = transitionContext. ContainerView fromCtrl. The alpha = 0.5 toView. Frame = presentingDirection.offsetF(withFrame: finalCtrlFrame) containerView.bringSubviewToFront(toView) UIView.animate(withDuration: transitionDuration(using: TransitionContext), Delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .curveLinear) { toView.frame = finalCtrlFrame } completion: { _ in let success = ! transitionContext.transitionWasCancelled transitionContext.completeTransition(success) } } }Copy the code
Two key
FromCtrl. View. Alpha = 0.5
This one guarantees that when we leave the scene,
From. view doesn’t block toCtrl.view completely
containerView.bringSubviewToFront(toView)
This ensures that toCtrl.view will not be lost after the exit
Better solution idea
Animation is a snapshot thing,
I have a FROM controller on my left hand and a to controller on my right hand, and I’ll just lay it out
class CustomDismissController: NSObject, UIViewControllerAnimatedTransitioning{ fileprivate var presentingDirection: PresentingDirection init(direction orientation: PresentingDirection) { presentingDirection = orientation } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 1 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from), let toCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to), let toView = toCtrl.view, let snapshot = toView.snapshotView(afterScreenUpdates: true) else{ return } let finalCtrlFrame = transitionContext.finalFrame(for: fromCtrl) let containerView = transitionContext.containerView snapshot.frame = presentingDirection.offsetF(withFrame: finalCtrlFrame) containerView.addSubview(snapshot) containerView.bringSubviewToFront(toView) toView.frame = finalCtrlFrame UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .curveLinear) { snapshot.frame = finalCtrlFrame } completion: { _ in snapshot.removeFromSuperview() let success = ! transitionContext.transitionWasCancelled transitionContext.completeTransition(success) } } }Copy the code
details
In the code above, if I tweak it,
Take the snapshot of the from controller, put it at the bottom,
Take the view of the TO controller, put it on top of the snapshot of the FROM controller, and animate it
Found, can not be placed up. Setting is invalid
Also, the view of the to controller, removed from the superview, can’t be retrieved
Another way to think about it
The view of the FROM controller, which is above the view of the to controller,
You can change the background color of the FROM controller to transparent and hide everything
example
Here’s the exit animation, which is a little more complicated,
Use keyframe animation, add a few steps
class FlipDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning { private let destinationFrame: CGRect let interactionController: SwipeInteractionController? init(destinationFrame: CGRect, interactionController: SwipeInteractionController?) { self.destinationFrame = destinationFrame self.interactionController = interactionController } func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 3 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromVC = transitionContext.viewController(forKey: .from), let toVC = transitionContext.viewController(forKey: .to), let toView = toVC.view, let snapshot = fromVC.view.snapshotView(afterScreenUpdates: false) else { return } snapshot.layer.cornerRadius = CardViewController.cardCornerRadius snapshot.layer.masksToBounds = true let containerView = transitionContext.containerView containerView.addSubview(snapshot) if let fromC = fromVC as? RevealViewController{ fromC.imageView.isHidden = true fromC.view.backgroundColor = UIColor.clear } AnimationHelper.perspectiveTransform(for: containerView) toView.layer.transform = AnimationHelper.yRotation(-.pi / 2) let duration = transitionDuration(using: transitionContext) containerView.bringSubviewToFront(toView) UIView.animateKeyframes( withDuration: duration, delay: 0, options:. CalculationModeCubic, animations: {uiView. addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 1/3) { snapshot.frame = self.destinationFrame } UIView.addKeyframe(withRelativeStartTime: 1/3, relativeDuration: 1/3) { snapshot.layer.transform = AnimationHelper.yRotation(.pi / 2) } UIView.addKeyframe(withRelativeStartTime: Two-thirds, relativeDuration: 1/3) {toView. Layer. The transform = AnimationHelper. YRotation (0.0)}}, completion: { _ in snapshot.removeFromSuperview() if transitionContext.transitionWasCancelled { containerView.sendSubviewToBack(toView) } transitionContext.completeTransition(! transitionContext.transitionWasCancelled) }) } }Copy the code
Finally, fill in the foundation
Transition animation structure drawing:
- Every controller has a property,
transitioningDelegate
By the method of UIViewControllerTransitioningDelegate agreement to provide the corresponding special animations
- Transition context
Transitioning Context
Context is everything
You can get the left hand FROM controller, and the right hand to controller from inside,
Frame corresponding to the controller
You can also take the from and to views directly from the context,
Personally, not much
- The animation is done,
Calls the method completeTransition(_:), which gives feedback to the system framework on the completion of the animation