This article records and shares the implementation method of custom transfer animation, specific to the animation effect: Sina Weibo atlas browsing transfer effect, gesture transition animation, NetEase Music start screen transfer animation, open and close animation, full screen slide back to the effect of the code can be downloaded to Github WSLTransferAnimation view, annotations are still clear.
Modal present and dismiss custom transitions
Create an animated transition managed object that follows the protocol and implement the following two methods:
/ / return the animation event - (NSTimeInterval) transitionDuration: (nullable id < UIViewControllerContextTransitioning >) transitionContext {return0.3; } / / all the transition animation affairs finish the - (void) within this method animateTransition: (id < UIViewControllerContextTransitioning >) transitionContext { UIViewController * fromVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController * toVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; / / remove the ferry before and after the view on the view controller view UIView * toView = [transitionContext viewForKey: UITransitionContextToViewKey]; UIView * fromView = [transitionContext viewForKey:UITransitionContextFromViewKey]; // There's an important concept here, containerView, where you can animate a view by adding it to the containerView, You can understand that containerView manages all views that do transitions UIView *containerView = [transitionContext containerView]; // If the gesture interaction transition is added, the operation needs to be performed according to whether the gesture interaction is completed/cancelled. Mark YES for completion and mark NO for cancellation. Otherwise, the system considers it is still in the animation process. There are bugs like transitionContext completeTransition:![transitionContext transitionWasCancelled]];if([transitionContext transitionWasCancelled]) {// If the transition is cancelled}else{// Complete transition}}Copy the code
2, a custom gesture of inheritance in UIPercentDrivenInteractiveTransition transition management object, according to the percentage of the gestures you need to set up animation ferry schedule.
/ / necessary call method / / gestures in the process of the system, through setting animated transitions process updateInteractiveTransition percentage, then the system will according to the percentage of automatic layout animation controls, Don't we control the [self updateInteractiveTransition: percentComplete]; / / complete ferry operation [self finishInteractiveTransition]; / / cancel the ferry operation [self cancelInteractiveTransition];Copy the code
3. The topmost view controller needs to follow the protocol during transition, and set it as a proxy, and implement the following proxy method:
/ / set the transitions agent self. TransitioningDelegate = self;#pragma mark -- UIViewControllerTransitioningDelegate// Returns an object that handles the present animation transition -(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presentingsourceController:(UIViewController *)source{
returnself.transitionAnimation; } // Return an object that handles the dismiss animation transition - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{ / / here we initialize dismissType self. TransitionAnimation. TransitionType = WSLTransitionOneTypeDissmiss;returnself.transitionAnimation; } // Return a nullable ID that handles the present gesture transition <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator{returnself.transitionInteractive; } / / return a handle dismiss gesture transitional object - (nullable id < UIViewControllerInteractiveTransitioning >) interactionControllerForDismissal: (id <UIViewControllerAnimatedTransitioning>)animator{return self.transitionInteractive;
}
Copy the code
Navigation controllers push and POP customize transitions
1, a little… 2. 3. Set the transition animation agent of the navigation controller before the push animation. The top view controller needs to follow the protocol during the transition, and set it as the agent, and implement the following proxy method:
/ / before push animation animate transitions agent self. The navigationController. Delegate = animationFour;#pragma mark -- UINavigationControllerDelegate// Return the nullable ID that handles push/ POP transitions <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{if (operation == UINavigationControllerOperationPush) {
self.transitionAnimation.transitionType = WSLTransitionTwoTypePush;
return self.transitionAnimation;
}else if (operation == UINavigationControllerOperationPop){
self.transitionAnimation.transitionType = WSLTransitionTwoTypePop;
}
returnself.transitionAnimation; } // Return the object that handles the push/pop gesture transition. This agent actually controls the percentage of the animation process above it based on the percentage of interactions - (nullable ID) <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{ // Gesture transition agent should be passed in at the beginning of the gesture, if pop or push is direct, return nil, otherwise pop/push cannot be completed properlyif ( self.transitionAnimation.transitionType == WSLTransitionTwoTypePop) {
return self.transitionInteractive.isInteractive == YES ? self.transitionInteractive : nil;
}
return nil;
}
Copy the code
Full screen sideslip return
Create an object named WSLNavigatioController that inherits from UINavigationController and implements the following method:
/ / acquisition system with sliding gesture of target object id target = self. InteractivePopGestureRecognizer. Delegate; // Create a full-screen swipe gesture, UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget: Target action:@selector(handleNavigationTransition:)]; Pan. Delegate = self; pan. Delegate = self; // Add a full-screen swipe gesture to navigation controller's View [self.view addGestureRecognizer:pan]; The sliding system at / / it is prohibited to use gestures to the self. The interactivePopGestureRecognizer. Enabled = NO;#pragma mark -- UIGestureRecognizerDelegate// When to invoke: Each time the gesture is triggered, the proxy is asked if it is triggered. / / function: intercept gestures trigger - (BOOL) gestureRecognizerShouldBegin: (gestureRecognizer UIGestureRecognizer *) {/ / note: Only non-root controllers have slide-back functionality, not root controllers. // Check whether the navigation controller has only one child controller. If there is only one child controller, it must be the root controllerif(self. ChildViewControllers. Count = = 1) {/ / user in the root controller interface, there is no need to trigger the sliding gestures,return NO;
}
return YES;
}
Copy the code
Resolve the conflict between the UIScrollView swipe gesture and the full screen swipe gesture
Create a UIScrollView category UIScrollView+GestureConflict and override the following method:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ // First check otherGestureRecognizer is the system POP gestureif ([otherGestureRecognizer.view isKindOfClass:NSClassFromString(@"UILayoutContainerView"// Determine whether the state of the gesture began or fail, and determine whether the position of the scrollView is exactly to the leftif (otherGestureRecognizer.state == UIGestureRecognizerStateBegan && self.contentOffset.x == 0) {
returnYES; }}return NO;
}
Copy the code
IOS full screen swipe gesture /UIScrollView/UISlider swipe gesture conflict