Swift explanation ------------ custom UINavigationController push and pop animation,
Customize the push and pop animation of UINavigationController
Create a simple project, drag a navigation controller in the storyboard, and change rootViewController to our ViewController.
To implement Custom Animation switching, we need to implement two protocols.UIViewControllerAnimatedTransitioning
,UINavigationControllerDelegate
The UIViewControllerAnimatedTransitioning Protocol aims to focus on the implementation of the animation, while using custom animations without affecting other attributes of the view, then, you can write Custom Animation code in the callback of this Protocol to switch the specific content. Any object implementing this Protocol is called an animation controller.
There are two important methods:
transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeIntervalanimateTransition(transitionContext: UIViewControllerContextTransitioning)
The first one returns the duration of an animation, and the second is the animation body.transitionContext
Here is a core. This object can be used to obtain context information during the switchover, for example, from which VC to which VC.
Let toViewController = transitionContext. viewControllerForKey (response); // let fromViewController = transitionContext. viewControllerForKey (response); let container = transitionContext. containerView () container !. AddSubview (toViewController ?. View )!); If response = UINavigationControllerOperation. Push {toViewController ?. View. layer. anchorPoint = CGPointMake (0, 0) toViewController ?. View. center = CGPointMake (0, 0) toViewController ?. View. transform = CGAffineTransformMakeRotation (CGFloat (-M_PI_2) UIView. animateWithDuration (self. transitionDuration (transitionContext), delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.7, options: UIViewAnimationOptions. allowUserInteraction, animations: {()-> Void in toViewController ?. View. transform = CGAffineTransformMakeRotation (0)}, completion: {(B)-> Void in toViewController ?. View. transform = CGAffineTransformIdentity // The animation is completed. // if the execution is canceled, the transitionContext. completeTransition (! TransitionContext. transitionWasCancelled ()} else if response = UINavigationControllerOperation. Pop {toViewController ?. View. layer. anchorPoint = CGPointMake (1, 0) // Do not be stupid between 0 and 1 .. ToViewController ?. View. center = CGPointMake (toViewController !. View. bounds. width, 0) toViewController ?. View. transform = CGAffineTransformMakeRotation (CGFloat (-M_PI_2 * 3) UIView. animateKeyframesWithDuration (1.3, delay: 0, options: UIViewKeyframeAnimationOptions. allowUserInteraction, animations: {()-> Void in UIView. addKeyframeWithRelativeStartTime (0.0, relativeDuration: 0.4, animations: {()-> Void in toViewController ?. View. transform = convert (CGFloat (-M_PI_2) * 4)}) UIView. addKeyframeWithRelativeStartTime (0.4, relativeDuration: 0.2, animations: {()-> Void in toViewController ?. View. transform = convert (CGFloat (M_PI_2/10)}) UIView. addKeyframeWithRelativeStartTime (0.6, relativeDuration: 0.3, animations: {()-> Void in toViewController ?. View. transform = CGAffineTransformMakeRotation (CGFloat (-M_PI_2) * 4)}, completion: {(B)-> Void in toViewController ?. View. transform = CGAffineTransformIdentity print (transitionContext. transitionWasCancelled () // The animation is completed // if the execution is canceled, the transitionContext. completeTransition (! TransitionContext. transitionWasCancelled ())})}
Here is a piece of code I wrote. Of course I have divided it into pop and push,oper
Variables are obtained from another method. To and from have nothing to say,container
This is a special container, and the animation during switching will be carried out in this container. Others are push and pop. I made an animation subject myself. Of course, you can change these parts as needed. Here we will mainly talk about customization, not animation.
We also need to implement another protocol.UINavigationControllerDelegate
This protocol is used to configure the interaction mode of some navigation controllers.
Define in our classvar navgationController:UINavigationController
During initialization
init(nav:UINavigationController){ self.navgationController = nav super.init() self.navgationController.delegate = self }
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { oper = operation return self }
The aboveoper
This is from here. We can see whether push or pop is currently in progress.return nil
The default animation is used,return self
It means we can use our own settings. If you only define one push or pop, you can add a judgment.
At this time, the effect should be as follows:
Gif is a bit choppy. It should all have a bullet effect... The source code will be provided later. You can run it yourself.
If you want to add this method to support gestures
Func navigationController (navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning)-> UIViewControllerInteractiveTransitioning? {/*** Monitoring progress */if animationController. isKindOfClass (MyAnimation. self) {return self. _ interactivePushTransition} return nil ;}
Then, write two gesture operations for push and pop respectively.
Func handleControllerPush (sender: UIPanGestureRecognizer) {let location = sender. translationInView (sender. view) var progress = location. x/(sender. view ?. Bounds. size. width )! // Print ("\ (location. x), \ (sender. view ?. Bounds. size. width )!) ") Progress = max (-1, min (progress, 0); let pz = progress *-1 // print (progress) if sender. state = UIGestureRecognizerState. start with the an {/*** gesture to create a new Monitored object */self. _ interactivePushTransition = UIPercentDrivenInteractiveTransition ()/*** tells the Controller to start executing the push animation */self. navgationController. pushViewController (toVc !, Animated: true)} else if sender. state = UIGestureRecognizerState. Changed {/*** update the progress of the gesture * // print (progress *-1) _ interactivePushTransition ?. UpdateInteractiveTransition (pz)} else if (sender. state = UIGestureRecognizerState. ended | sender. state = UIGestureRecognizerState. changed) {/*** if the progress is greater than half at the end of the gesture, the push operation is completed; otherwise, the operation is resumed. */Print (pz) if (pz> 0.14) {self. _ interactivePushTransition ?. FinishInteractiveTransition ()} else {self. _ interactivePushTransition ?. CancelInteractiveTransition ()} // it is important to set interactionController to nil when the animation switching is complete. If the next animation is non-interactive, we do not want to get a strange interactionController self. _ interactivePushTransition = nil }}
Pop won't be released. Download the code by yourself ..
Write your own navigation controller.
protocol MyPushNav{ func pushView()->UIViewController;}class MyNavigationController: UINavigationController { var pushDele:MyPushNav? var animate:MyAnimation? override func viewDidLoad() { super.viewDidLoad() animate = MyAnimation(nav: self); let pan = UIPanGestureRecognizer(target: animate, action: "handleControllerPop:") self.view.addGestureRecognizer(pan) } override func viewDidAppear(animated: Bool) { pushView(); } func pushView(){ let pan2 = UIPanGestureRecognizer(target: animate, action: "handleControllerPush:") if let _ = pushDele { let sc = pushDele?.pushView() self.animate?.toVc = sc (pushDele as! UIViewController).view.addGestureRecognizer(pan2) }else{ self.view.removeGestureRecognizer(pan2) } }}
If push is required, we must tell which push is used, so the protocol is used.
Pop does not require any operation.
class ViewController: UIViewController,MyPushNav { override func viewDidLoad() { super.viewDidLoad() (self.navigationController as! MyNavigationController).pushDele = self // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func pushView()->UIViewController { return SecondViewController() }}
This is push ..
Attached a useful graph for understanding
Source Code address: MyNavigationController
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.