preface

Normally, we use push, pop, present, and dismiss animations, which are nothing more than the default push and push effects of the system. The model animation is better, there are four effects, while navigation has only one effect

If you want to use custom animation suitable for the scene, then you need to customize, such as: wechat view big picture, some transformation effects

Case demo

Custom transition animation

Model transition animation specific protocol

Model transition animation, also known as present, dismiss, set its transition animation to achieve the following two special methods

Note: it should be a ferry animation UIViewControllerAnimatedTransitioning implementation class (described later), the demo for convenience and extracted a Shared class, so a little different

// Present animation set method
/ / return UIViewControllerAnimatedTransitioning object of the agreement (described later)
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented 
    presentingController:(UIViewController *)presenting 
    sourceController:(UIViewController *)source;
    
// DissMiss animation set method
/ / return UIViewControllerAnimatedTransitioning object of the agreement (described later)
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
Copy the code

Navigation transition animation specific protocol

Navigation transition animation, also commonly known as push, pop, set its transition animation to implement the following two unique methods

Note: it should be a ferry animation UIViewControllerAnimatedTransitioning implementation class (described later), the demo for convenience and extracted a Shared class, so a little different

// An animation set method shared by push and pop
/ / return UIViewControllerAnimatedTransitioning object of the agreement (described later)
// The types of animations (push, pop) can be distinguished by operation enumeration types, as shown in the following enumeration
// Animation can be used as needed
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController 
    animationControllerForOperation:(UINavigationControllerOperation)operation 
    fromViewController:(UIViewController *)fromVC 
    toViewController:(UIViewController *)toVC;
Copy the code

Operation, as shown below, is the operation type of a transition animation, usually push or POP

typedef NS_ENUM(NSInteger, UINavigationControllerOperation) {
    UINavigationControllerOperationNone,
    UINavigationControllerOperationPush,
    UINavigationControllerOperationPop,
};
Copy the code

General transitions animation protocol (UIViewControllerAnimatedTransitioning)

Custom transitions is UIViewControllerAnimatedTransitioning animation in order to realize the core of the agreement, both in mode and navigation to achieve this agreement, the frequently used method has the following two:

// Set the animation execution time
- (NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)
transitionContext;

// Custom animation implementation method, transitionContext contains the animation required variables
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext
Copy the code

Instead of setting the time of the animation, the animateTransition: is how we write the transition animation. Here is an example, and then we will introduce the other properties

- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
    // Get controller before change, top controller before push (pop reverse)
    UIViewController *fromVc = [transitionContext 
        viewControllerForKey:UITransitionContextFromViewControllerKey];
    // Get the changed controller, push the top controller (pop reverse)
    UIViewController *toVc = [transitionContext 
        viewControllerForKey:UITransitionContextToViewControllerKey];
        
    // add tovc. view to the containerView
    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:toVc.view];
    
    // Use UIView animation to transform layers
    [UIView 
        transitionFromView:fromVc.view 
        toView:toVc.view 
        duration:[self transitionDuration:transitionContext] 
        options:UIViewAnimationOptionTransitionFlipFromLeft 
        completion:^(BOOL finished) {
        // After the transition animation is complete, the tag transformation is complete
        [transitionContext completeTransition:YES];
    }];
}
Copy the code

Above is a Flip animation, which can be applied to mode and navigation. I believe it is very easy to see, so I will continue the introduction step by step

Realized UIViewControllerContextTransitioning agreement transitionContext? What are the commonly used method

ContainerView: The bottom view of the container is currently displayed. You need to add the ToViewController layer to it, otherwise the current controller layer will not be displayed. You can add and remove new layers while changing layers, and perform more complicated transition animations

CompleteTransition: : After completing the animation, the tag transformation ends to complete the other processing of the process system

ViewControllerForKey: : With the transitionContext parameter, you can retrieve fromViewController and toViewController from this method by adding some keys, i.e. push, pop, and other view controllers, with two keys: UITransitionContextFromViewControllerKey, UITransitionContextToViewControllerKey, to believe that they know the meaning of the expression, the name is respectively before and after the transformation of the from – > to controller

ViewForKey: : Similar to viewControllerForKey, gets controller view parameters and returns UIView parameters, respectively: UITransitionContextFromViewKey, UITransitionContextToViewKey, respectively before and after the transformation of the controller inside the view

InitialFrameForViewController, finalFrameForViewController: two parameters for reference, for the controller before and after the transformation of frame information, reference, used as a animation or animation to use when processing

AnimationEnded: Push, pop Whether animations are applied for animation control. This parameter is optional

So containerView is basically the bottom view of the UI, and when we animate it, we need to add the View view of the toViewController so that the new page will display properly

So the view that we add to containerView doesn’t go away, so be careful when you animate it

ContainerView with screenshots solution snapshotViewAfterScreenUpdates: combine can make more complex animation effects, but the interference of the original layers from the animation

// The specified screenshot can be drawn to generate a new View layer, which can be used for animation layer transformation display
// Can be interpreted as an imageView image
UIView *fromView = [fromVc.view snapshotViewAfterScreenUpdates:YES];
UIView *toView = [toVc.view snapshotViewAfterScreenUpdates:YES];
Copy the code

Through above snapshotViewAfterScreenUpdates method to generate the view, as a temporary view transformation layer when using transformation, to make complex animation, without affecting the real viewController layer

Principle of animation: it is understandable to add an identical layer on top of the original layer, transform it into the same style as the original layer, then remove it instantly, so that the user sees the same effect as the original layer

Here is a screenshot of a push like effect, starting with the screenshot and even preparing for the animation

In addition, if a complex animation uses the CoreAnimation API, its proxies can be used to properly monitor the start and end of the animation

UIViewController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// add tovc. view to the containerView
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toVc.view];

// Create new screenshots from the original layer to facilitate transition animation
UIView *fromView = [fromVc.view snapshotViewAfterScreenUpdates:YES];
UIView *toView = [toVc.view snapshotViewAfterScreenUpdates:YES];

/ high/wide access to view, you can use finalFrameForViewControllerc obtain frame to deal with, here for the convenience of direct use
CGFloat width = fromView.frame.size.width;
CGFloat height = fromView.frame.size.height;

// Set the state of the viewFrame before the animation transitions. You can scale (Rotation), gradient (alpha)
fromView.frame = CGRectMake(0.0, width, height);
toView.frame = CGRectMake(-width, 0, width, height);

// Add the transition animation layer to containerView to display the transition animation
[containerView addSubview:fromView];
[containerView addSubview:toView];

// Start the transition animation
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
    fromView.frame = CGRectMake(width, 0, width, height);
    toView.frame = CGRectMake(0.0, width, height);
} completion:^(BOOL finished) {
    // After the transition animation is complete, remove the two transition animation layers added after the transition animation layer view
    [fromView removeFromSuperview];
    [toView removeFromSuperview];
    [transitionContext completeTransition:YES];
}];

// When you use the animation, you need to set the agent so that you can get the time when the animation starts and ends
// CABasicAnimation *basic;
// basic.delegate = self;
// - (void)animationDidStart:(CAAnimation *)anim;
// - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
Copy the code

It can be seen that using the screenshot method, the following three steps are roughly gone through:

1. Obtain the view controllers fromViewController and toViewController before and after the control transition animation transformation

2. Add the toViewController view to the containerView to display the transformed controller layer. If there is no animation at this point, you’re done (just call completeTransition).

3, here we are to start the production of animation, simple animation, you can directly use the original layer for transformation operations, complex can use screenshots to do

3.1 Ordinary animation production, the premise is not to interfere with the original layer, directly use the original layer, directly use the system’s animation method for transformation, after the end of the animation, use completeTransition to mark the end of transformation

3.2 Complex animation production, all kinds of magic oil, whether to interfere with the original layer or not, can be used, but the logic is slightly more complex, the more complex animation processing logic

3.2.1 complex animation as a first step, first screenshot processing, use snapshotViewAfterScreenUpdates method, obtaining new layer, and then added to the containerView above

3.2.2 Before setting the animation style, if it is pan advance, then handle the position well; If it’s a zoom, set the zoom point and the magnification ahead of time, and make sure the style is the same as the original fromViewContoller style

3.2.3 Set the style after the animation transition, and the style after the transition should be the same as the original style of toViewController, no matter the position or size, etc. (If the transition animation is troublesome, it may be divided into several steps, in any case, the start and end style should be the same as the original style)

3.2.4 After the transition animation is complete, remove the duplicate layer added to containerView and call completeTransition to mark the transition

The last

For the gesture issues on the previous page of POP, refer to the previous article: Navigation and some issues with gestures

Come to try some custom transition animation, might as well do a copy of wechat picture amplification effect