Simple custom ViewController jump animation

See iOS in the study of animation, the animation has been cool to others is my motivation, learning how to customize that is actually not so difficult, some gradient, flip, translation can be achieved in the UIView animation can jump into animation, you can also finish the example, share a GitHub on others do cool animation:

Simple custom ViewController jump animation


When we view switching, whether push, pop or by PresentModal and dismiss, we can put the jump animation is divided into three parts: the first 1
view controller display.
2: the temporary view controller shows the animation effect (does not really exist; the controller is actually only one containerView)
3: displays second view controllers.
with the image of a point of view, we can add second part as a temporary view controller, he performed a UIView animation, as long as we make animation start interface with the controller 1, the end of the interface and the view controller 2. When the animation execution finishes and executes to the third step, the temporary view controller is released. In this way, just a few implementations of UIView, CALayer animation, and
specific implementations are shown in the following diagram:

Simple custom ViewController jump animation
jump animation Demo.gif

Protocols and methods used

@protocol UIViewControllerAnimatedTransitioning

The object of this protocol is equivalent to the temporary view controller mentioned earlier. The two main protocols used in the protocol are:

/ / this method we simply return the page Jump animation execution time (NSTimeInterval) - transitionDuration: (ID < UIViewControllerContextTransitioning > transitionContext); / / implementation of animation in this method - (void) animateTransition: (ID < UIViewControllerContextTransitioning > transitionContext);

The second method is to jump to animate the kernel content. The parameter transitionContext in the method is the context of the current temporary controller interface. Through the context, we first get the background view containerView of the temporary view controller, and he already has a sub view, that is, fromViewController.view. All we have to do is get toViewController first

UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

Then add the current view to the content view

[[transitionContext containerView] addSubview:toVC.view];

The rest of the system can take advantage of the learning level of our system’s core animation, such as modifying toVC.view’s frame, spinning from the bottom, and so forth. To achieve the Demo effect, we need to do CAShapeLayer toView occlusion, then from the modified ShapeLayer.path attribute from a small round into a circle round circle includes full screen, we painted by UIBezierPath, ShapeLayer and UIBezierPath for unfamiliar students can go to cram, here the specific use is not complicated also, can learn directly to see the following code.

The application of #define / / mainScreen].bounds.size.height / / [UIScreen screen height kWindowH application #define kWindowW [UIScreen mainScreen].bounds.size.width screen width

_circleCenterRect = CGRectMake (120, 320, 50, 50); / / *smallCircleBP = [UIBezierPath UIBezierPath small circle 1-- bezierPathWithOvalInRect:_circleCenterRect]; / / 2-- / / _circleCenterRect circle circle in the center of CGFloat centerX CGFloat = _circleCenterRect.origin.x+_circleCenterRect.size.width/2; centerY = _circleCenterRect.origin.y+_circleCenterRect.size.height/2; / / find the center to page 4 corners of the longest distance as the radius of CGFloat = R1 (kWindowW-centerX) > centerX? (kWindowW-centerX): centerX; CGFloat = R2 (kWindowW-centerY) > centerY? (kWindowW-centerY): centerY; CGFloat = sqrt (radius (R1 * R1) + (R2 * R2)); UIBezierPath *bigCircleBP = [UIBezierPath bezierPathWithOvalInRect: CGRectInset (_circleCenterRect, -radius, -radius)];

After the circle is finished, execute by CABasicAnimation:

Set maskLayer CAShapeLayer = [CAShapeLayer *maskLayer / / layer] / / path; it will be designated as the final path to avoid in the animation will rebound after the completion of toVC.view.layer.mask = maskLayer; maskLayer.path = bigCircleBP.CGPath; / / CABasicAnimation = [CABasicAnimation * maskLayerAnimation animation executive animationWithKeyPath:@ "path"]; maskLayerAnimation.fromValue (__bridge = ID) (smallCircleBP.CGPath); maskLayerAnimation.toValue (__bridge = ID) ((bigCircleBP.CGPath)); maskLayerAnimation.duration [self = transitionDuration:transitionContext]; maskLayerAnimation.delegate = self; [maskLayer addAnimation:maskLayerAnimation forKey:@ "path"];

Return time animation and the code above is basically the same, only the large and small round order reversed, the core part of the animation after the jump is how to use the object, both the navigation and the modal system jump, have provided us with a callback method, we only need to implement the method, and then put before us this animation will return the object. Since you added shapelayer to the view, you can implement it in the CABasicAnimation proxy method.

- (void) animationDidStop: (CAAnimation *) anim finished: (BOOL) flag{/ transition [self.transitionContext tells the system that this completeTransition:! [self.transitionContext transitionWasCancelled]] fromVC mask; / / remove [self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil [self.transitionContext; viewControllerForKey:UITransitionContextToViewControllerKey].view.layer.mask = nil;}
@protocol UINavigationControllerDelegate

This is to modify the Navigation jump animations need to implement the agreement, when we through pop or push to jump when the method calls the following (other methods of protocol due to temporary use, so not introduced), we can see the return value is ID < UIViewControllerAnimatedTransitioning>, is that we’ve written the animation object.

- (nullable ID < UIViewControllerAnimatedTransitioning> navigationController:) (UINavigationController *) navigationController animationControllerForOperation: (UINavigationControllerOperation) operation fromViewController: (UIViewController * fromVC) toViewController: (UIViewController * toVC);

The operation parameter method is an enumeration type, we can determine its value is UINavigationControllerOperationPush or
UINavigationControllerOperationPop to distinguish the jump.

@protocol UIViewControllerTransitioningDelegate

This is the protocol that needs to be implemented to modify the modal jump animation. We will call the two methods when we jump PresentModal and dismiss:

//PresentModal (nullable ID - jump callback method < UIViewControllerAnimatedTransitioning> animationControllerForPresentedController:) (UIViewController *) presented presentingController: (UIViewController * presenting) sourceController: (UIViewController *) source; //dismiss (nullable ID jump callback method - < UIViewControllerAnimatedTransitioning> animationControllerForDismissedController:) (UIViewController * dismissed);

The return value of these two methods is the same as the return value of the above navigation callback method. We only need to initialize our animation object for implementing the UIViewControllerTransitioningDelegate protocol. Specific implementation and effect, you can see the end of the article attached to the Demo.

Navigation jump needs attention

When using the Navigation jump, we want view 1 to jump to view 2 and view 2 to return view 1, when we have custom animations, we will only set navigation of view 1 in view 1. Second, delegate settings are best placed in viewWillAppear.

The final effect achieved by demo only occurs when the button is clicked, rather than the gesture animation like navigation’s side slip back. How to avoid the effect of sideslip is not uniform, we can first return the effect of sideslip closed:

Self.navigationController.interactivePopGestureRecognizer.enabled = NO;

TODO: / / implementation method of gesture animation jump (pit to fill)

GitHub Demo address
bestswifter version of the tutorial swift