IOS custom transfer animation (lower)
Add UIViewControllerAnimatedTransitioning
Add a Cocoa Touch Class, inherit from NSObject, and name it BWFlipTransionPush (the name is nice .), Comply with the UIViewControllerAnimatedTransitioning protocol.
Two methods for implementing the Protocol, and write the Push animation in it. The specific animation implementation process is included in the code comment:
Func animateTransition (transitionContext: UIViewControllerContextTransitioning ){
LetfromVC = transitionContext. viewControllerForKey (UITransitionContextFromViewControllerKey)! FirstViewController
LettoVC = transitionContext. viewControllerForKey (UITransitionContextToViewControllerKey)! SecondViewController
Letcontainer = transitionContext. containerView ()
Container. addSubview (toVC. view)
Container. bringSubviewToFront (fromVC. view)
// Change m34
Vartransfrom = CATransform3DIdentity
Transfrom. m34 =-0.002
Container. layer. sublayerTransform = transfrom
// Set anrchPoint and position
LetinitalFrame = transitionContext. initialFrameForViewController (fromVC)
ToVC. view. frame = initalFrame
FromVC. view. frame = initalFrame
FromVC. view. layer. anchorPoint = CGPointMake (0, 0.5)
FromVC. view. layer. position = CGPointMake (0, initalFrame. height/2.0)
// Add a shadow effect
LetshadowLayer = CAGradientLayer ()
ShadowLayer. colors = [UIColor (white: 0, alpha: 1 ). CGColor, UIColor (white: 0, alpha: 0.5 ). CGColor, UIColor (white: 1, alpha: 0.5)]
ShadowLayer. startPoint = CGPointMake (0, 0.5)
ShadowLayer. endPoint = CGPointMake (1, 0.5)
ShadowLayer. frame = initalFrame
Letshadow = UIView (frame: initalFrame)
Shadow. backgroundColor = UIColor. clearColor ()
Shadow. layer. addSublayer (shadowLayer)
FromVC. view. addSubview (shadow)
Shadow. alpha = 0
// Animation
UIView. animateWithDuration (transitionDuration (transitionContext), delay: 0, options: UIViewAnimationOptions. CurveEaseOut, animations: {()-> Voidin
FromVC. view. layer. transform = CATransform3DMakeRotation (CGFloat (-M_PI_2), 0, 1, 0)
Shadow. amp; alpha = 1.0
}) {(Finished: Bool)-> Voidin
FromVC. view. layer. anchorPoint = CGPointMake (0.5, 0.5)
FromVC. view. layer. position = CGPointMake (CGRectGetMidX (initalFrame), CGRectGetMidY (initalFrame ))
FromVC. view. layer. transform = CATransform3DIdentity
Shadow. removeFromSuperview ()
TransitionContext. completeTransition (! TransitionContext. transitionWasCancelled ())
}
}
I will not talk much about the animation process. I will understand it after careful reading.
Use Animation
Make FirstViewController comply with the UIViewControllerTransitioningDelegate protocol, and set self. transitioningDelegate to self.
Two methods for implementing the UIViewControllerTransitioningDelegate protocol are used to specify the animation class.
// Animation Push
Func animationControllerForPresentedController (presented: UIViewController, presentingControllerpresenting: UIViewController, sourceControllersource: UIViewController)-> UIViewControllerAnimatedTransitioning? {
ReturnBWFlipTransionPush ()
}
// Animated Pop
Func animationControllerForDismissedController (dismissed: UIViewController)-> UIViewControllerAnimatedTransitioning? {
ReturnBWFlipTransionPop ()
}
OK. If you have completed the Pop animation, you can now customize Modal transfer. Now it's just a gesture drive.
Gesture-driven
To implement Push and Pop gestures at the same time, you need to add gestures to two viewController. Views. First, add a gesture to the right of the screen to the FirstViewController, and add a gesture to the left of the screen to SecondViewController. view in the prepareForSegue () method so that they can use the same gesture listening method.
The method for implementing the listener is the same as before, but you should take a closer look, because the transfer field animation in this example is special and there are two gestures, so the percentage calculation here uses KeyWindow. Do not forget the UIPercentDrivenInteractiveTransition attribute.
Func edgePanGesture (edgePan: UIScreenEdgePanGestureRecognizer ){
Letprogress = abs (edgePan. translationInView (UIApplication. sharedApplication (). keyWindow !). X)/UIApplication. sharedApplication (). keyWindow !. Bounds. width
IfedgePan. state = UIGestureRecognizerState. Began {
Self. percentDrivenTransition = UIPercentDrivenInteractiveTransition ()
IfedgePan. edges = UIRectEdge. Right {
Self. inclumseguewithidentifier ("present", sender: nil)
} ElseifedgePan. edges = UIRectEdge. Left {
Self. dismissViewControllerAnimated (true, completion: nil)
}
} ElseifedgePan. state = UIGestureRecognizerState. Changed {
Self. percentDrivenTransition ?. UpdateInteractiveTransition (progress)
} ElseifedgePan. state = UIGestureRecognizerState. Cancelled | edgePan. state = UIGestureRecognizerState. Ended {
Ifprogress & gt; 0.5 {
Self. percentDrivenTransition ?. FinishInteractiveTransition ()
} Else {
Self. percentDrivenTransition ?. CancelInteractiveTransition ()
}
Self. percentDrivenTransition = nil
}
}
The other two methods that implement the UIViewControllerTransitioningDelegate protocol return the percentages of the Present and Dismiss animations respectively.
// Percentage Push
Func interactionControllerForPresentation (animator: UIViewControllerAnimatedTransitioning)-> UIViewControllerInteractiveTransitioning? {
Returnself. percentDrivenTransition
}
// Percentage Pop
Func interactionControllerForDismissal (animator: UIViewControllerAnimatedTransitioning)-> UIViewControllerInteractiveTransitioning? {
Returnself. percentDrivenTransition
}
Now, the Modal-based custom transition animation example is complete. Obtain the complete source code: FlipTransion
Segue
This method is special. It is used to bind the drag and drop lines in the Stroyboard with the custom UIStoryboardSegue class to customize the transition process animation.
First, let's take a look at what UIStoryboardSegue looks like.
@ Availability (iOS, introduced = 5.0)
ClassUIStoryboardSegue: NSObject {
// Convenience constructor for returning a segue that performs a handler block in its-perform method.
@ Availability (iOS, introduced = 6.0)
Convenience init (identifier: String ?, Source: UIViewController, destination: UIViewController, javasmhandler :()-> Void)
Init! (Identifier: String ?, Source: UIViewController, destination: UIViewController) // Designated initializer
Varidentifier: String? {Get}
VarsourceViewController: AnyObject {get}
VardestinationViewController: AnyObject {get}
Func perform ()
}
The above is the definition of UIStoryboardSegue class. We can see that there is only one method, perform (), so it is obvious that this method is rewritten to customize the transition animation.
Pay attention to its other attributes: sourceViewController and destinationViewController. With these two attributes, we can access the two protagonists in a transition animation, so that we can customize the animation as we like.
Note only one point: when dragging a line, select custom in the pop-up options. Then you can bind it to the custom UIStoryboardSegue.
So the question is, here only the perform is available. What should we do with the animation returned? Please refer to the following link:
Dismiss
Since the perfrom method is called: segue, the previous controller returned to the transfer is called: unwind segue.
The unwind track usually appears together with the normal custom track.
To cancel the transition, we must override the perform method and apply the Custom Animation. In addition, the transition effect of the navigation back source View Controller does not need to be the same as that of the corresponding normal transition.
The implementation steps are as follows:
Create an IBAction method that selectively executes some code when the transfer is canceled. This method can have any name you want and does not include anything else. It needs to be defined, but can be left blank. This method is required to remove the definition of transfer.
Release the transfer creation and configuration. This is not the same as the previous transfer creation. Let's wait and see how this is implemented.
You can override the perform () method in the UIStoryboardSegue subclass to implement Custom Animation.
The UIViewController class provides the definition of a specific method, so the system knows that the transfer is about to be executed.
Of course, there are some things that are hard to understand and do not know what it means. Next, let's take a further look at it through an example.
Example
This example is written by myself. The Source Code address is SegueTransion.
Create two uiviewcontrollers named FirstViewController and SecondViewController respectively. Add two uiviewcontrollers to the Storyboard and bind them.
Add a background image to the two controllers or use a different background color for distinguishing. Add a trigger button in FirstViewController, drag the button to SecondViewController, and select custion in the pop-up options.
Add a Cocoa Touch Class that inherits from UIStoryboardSegue and is named FirstSegue ). And bind it to the segue dragged in the previous step.
Override the perform () method in FirstSegue and write the animation logic in it.
Override func perform (){
VarfirstVCView = self. sourceViewController. viewasUIView!
VarsecondVCView = self. destinationViewController. viewasUIView!
LetscreenWidth = UIScreen. mainScreen (). bounds. size. width
LetscreenHeight = UIScreen. mainScreen (). bounds. size. height
SecondVCView. frame = CGRectMake (0.0, screenHeight, screenWidth, screenHeight)
Letwindow = UIApplication. sharedApplication (). keyWindow
Window ?. InsertSubview (secondVCView, aboveSubview: firstVCView)
UIView. animateWithDuration (0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: UIViewAnimationOptions. CurveLinear, animations: {()-> Voidin
SecondVCView. frame = CGRectOffset (secondVCView. frame, 0.0,-screenHeight)
}) {(Finished: Bool)-> Voidin
Self. sourceViewController. presentViewController (self. destinationViewControlleras! UIViewController,
Animated: false,
Completion: nil)
}
}
The animation process is quite simple.
Present gesture
Note that a custom transition animation cannot be dynamically driven by a gesture, that is, it cannot dynamically change the animation completion degree based on the gesture percentage.
Therefore, we simply add a slide gesture (swip ).
Add a gesture to FisrtViewController:
VarswipeGestureRecognizer: UISwipeGestureRecognizer = UISwipeGestureRecognizer (target: self, action: "showSecondViewController ")
SwipeGestureRecognizer. direction = UISwipeGestureRecognizerDirection. Up
Self. view. addGestureRecognizer (swipeGestureRecognizer)
How to Implement gesture listening:
Func showSecondViewController (){
Self. inclumseguewithidentifier ("idFirstSegue", sender: self)
}
Now the present is ready, and dismiss is implemented.
Dismiss
Add an IBAction method to FirstViewController. The method name can be used as needed.
On the Storyboard, select SecondViewController and press and hold the control key to drag the line to the Exit icon of SecondViewController. In the pop-up options, select the method for adding IBAction in the previous step.
In the document view on the left side of the Storyboard, find the last drag seue and Set identifier
Add a Cocoa Touch Class that inherits from UIStoryboardSegue and is named FirstSegueUnWind ). And rewrite its perform () method to implement the dismiss animation.
In FirstViewController, rewrite the following method. Determine whether or not dismiss is required based on the identifier. If yes, the created FirstUnWindSegue is returned.
Override func segueForUnwindingToViewController (toViewController: UIViewController, fromViewController: UIViewController, identifier: String ?) -> UIStoryboardSegue {
Ifidentifier = "firstSegueUnwind "{
ReturnFirstUnwindSegue (identifier: identifier, source: fromViewController, destination: toViewController, receivmhandler: {()-> Voidin
})
}
Returnsuper. segueForUnwindingToViewController (toViewController, fromViewController: fromViewController, identifier: identifier)
}