UIViewController transfer animation, uiviewcontroller

Source: Internet
Author: User

UIViewController transfer animation, uiviewcontroller
UIViewControllerAnimatedTransitioning

In UINavigationController, how does one use UIViewControllerAnimatedTransitioning?
Reference: How to use UIViewControllerAnimatedTransitioning with UINavigationController?

1. The FromViewController of the animation must follow the UINavigationControllerDelegate protocol.
2. In FromViewController, a custom transition animation object is returned in the following proxy method:

    - (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController                                   animationControllerForOperation:(UINavigationControllerOperation)operation                                                fromViewController:(UIViewController *)fromVC                                                  toViewController:(UIViewController *)toVC {        TransitionAnimator *animator = [TransitionAnimator new];        animator.presenting = (operation == UINavigationControllerOperationPush);        return animator;    }

3. To create a custom animation class, follow the UIViewControllerContextTransitioning Protocol and implement the following proxy methods:

-(NSTimeInterval) transitionDuration :( id <UIViewControllerContextTransitioning>) transitionContext {// return the animation execution time return 0.5f;}-(void) animateTransition :( id <interval>) transitionContext {// Grab the from and to view controllers from the contextUIViewController * fromViewController = [transitionContext viewControllerForKey: Secret]; UIViewController * toViewController = [transitionContext viewControllerForKey: Secret]; // Set our ending frame. we'll modify this later if we have toCGRect endFrame = CGRectMake (80,280,160,100); if (self. presenting) {fromViewController. view. userInteractionEnabled = NO; [transitionContext. containerView addSubview: fromViewController. view]; [transitionContext. containerView addSubview: toViewController. view]; CGRect startFrame = endFrame; startFrame. origin. x ++ = 320; toViewController. view. frame = startFrame; [UIView animateWithDuration: [self transitionDuration: transitionContext] animations: ^ {fromViewController. view. tintAdjustmentMode = UIViewTintAdjustmentModeDimmed; toViewController. view. frame = endFrame;} completion: ^ (BOOL finished) {[transitionContext completeTransition: YES] ;}] ;} else {toViewController. view. userInteractionEnabled = YES; [transitionContext. containerView addSubview: toViewController. view]; [transitionContext. containerView addSubview: fromViewController. view]; endFrame. origin. x ++ = 320; [UIView animateWithDuration: [self transitionDuration: transitionContext] animations: ^ {toViewController. view. tintAdjustmentMode = UIViewTintAdjustmentModeAutomatic; fromViewController. view. frame = endFrame;} completion: ^ (BOOL finished) {[transitionContext completeTransition: YES] ;}}}

For more information about UIViewControllerAnimatedTransitioning, see:

  • Easy to learn-iOS uses the Runtime custom controller POP gesture Animation
  • New Features of iOS 7: View Controller switching API
  • ViewController's advanced transfer Animation
  • View Controller Transfer

The following content is from
Introduction to Custom View Controller Transitions and Animations
To create a custom transition, follow these three steps:

  • Create a class that implements the UIViewControllerAnimatedTransitioning protocol. Here you will write code that performs the animation. This class is referred to as the animation controller.
  • Before presenting a view controller, set a class as its transitioning delegate. The delegate will get a callback for the animation controller to be used when presenting the view controller.
  • Implement the callback method to return an instance of the animation controller from the first step.
Custom Present Transition (Custom Present Transition)

First, create an animation controller. CreateCustomPresentAnimationControllerClass inherited from NSObject

class CustomPresentAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

The UIViewControllerAnimatedTransitioning protocol has two required methods.

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {    return 2.5}func animateTransition(transitionContext: UIViewControllerContextTransitioning) {    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)    let containerView = transitionContext.containerView()    let bounds = UIScreen.mainScreen().bounds    toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)    containerView.addSubview(toViewController.view)    UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .CurveLinear, animations: {        fromViewController.view.alpha = 0.5        toViewController.view.frame = finalFrameForVC        }, completion: {            finished in            transitionContext.completeTransition(true)            fromViewController.view.alpha = 1.0    })}

The current controller must follow the UIViewControllerTransitioningDelegate protocol.

class ItemsTableViewController: UITableViewController, UIViewControllerTransitioningDelegate {

UIViewController has a transitionDelegate attribute that supports custom transitions. When a View controller transitions to another View controller, the system checks this attribute to determine whether to use a custom transition. The custom transition is provided by UIViewControllerTransitioningDelegate.

let customPresentAnimationController = CustomPresentAnimationController()override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {    if segue.identifier == "showAction" {        let toViewController = segue.destinationViewController as UIViewController        toViewController.transitioningDelegate = self    }}func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {    return customPresentAnimationController}

If you want a different effect, you can use the code in CustomPresentAnimationController. swift:

toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)

Change the origin position of the View controller frame to the following format:

toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, -bounds.size.height)

Custom Dismiss Transition (Custom Dismiss Transition)

UIViewControllerTransitioningDelegateYou can also specify an animation controller to dismiss a view controller.
Create a CustomDismissAnimationController class that inherits from NSObject. As follows:

class CustomDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

Add the following code to this class:

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {    return 2}func animateTransition(transitionContext: UIViewControllerContextTransitioning) {    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)    let containerView = transitionContext.containerView()    toViewController.view.frame = finalFrameForVC    toViewController.view.alpha = 0.5    containerView.addSubview(toViewController.view)    containerView.sendSubviewToBack(toViewController.view)    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {        fromViewController.view.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)        toViewController.view.alpha = 1.0    }, completion: {        finished in        transitionContext.completeTransition(true)    })}

Add the following attributes to ItemsTableViewController:

let customDismissAnimationController = CustomDismissAnimationController()

Add the following methods to the class:

func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {    return customDismissAnimationController}

UIViewControllerTransitioningDelegateThe Protocol provides the above method, which is used to obtain the animation controller of the dismiss view controller.
The running result is as follows:

Animation effects are not what we want. The reason is that changing the frame of a view does not affect its subview. You can use snapshotting of UIView to modify it.
The snapsho of UIView is a screenshot of UIView, making it a lightweight UIView. We will use this screenshot in the animation process, rather than the real view.

Replace the animateTransition () function with the following form:

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!    let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)    let containerView = transitionContext.containerView()    toViewController.view.frame = finalFrameForVC    toViewController.view.alpha = 0.5    containerView.addSubview(toViewController.view)    containerView.sendSubviewToBack(toViewController.view)    let snapshotView = fromViewController.view.snapshotViewAfterScreenUpdates(false)    snapshotView.frame = fromViewController.view.frame    containerView.addSubview(snapshotView)    fromViewController.view.removeFromSuperview()    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {        snapshotView.frame = CGRectInset(fromViewController.view.frame, fromViewController.view.frame.size.width / 2, fromViewController.view.frame.size.height / 2)        toViewController.view.alpha = 1.0    }, completion: {        finished in        snapshotView.removeFromSuperview()        transitionContext.completeTransition(true)    })  }

Navigation controller transition)

The custom mnmnavigationanimationcontroller class inherits from NSObject, as follows:

class CustomNavigationAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

Add the following content to this class. Use a simple cube animation for this animation controller. A reverse variable is used to determine the animation direction.

var reverse: Bool = falsefunc transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {    return 1.5}func animateTransition(transitionContext: UIViewControllerContextTransitioning) {    let containerView = transitionContext.containerView()    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!    let toView = toViewController.view    let fromView = fromViewController.view    let direction: CGFloat = reverse ? -1 : 1    let const: CGFloat = -0.005    toView.layer.anchorPoint = CGPointMake(direction == 1 ? 0 : 1, 0.5)    fromView.layer.anchorPoint = CGPointMake(direction == 1 ? 1 : 0, 0.5)    var viewFromTransform: CATransform3D = CATransform3DMakeRotation(direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)    var viewToTransform: CATransform3D = CATransform3DMakeRotation(-direction * CGFloat(M_PI_2), 0.0, 1.0, 0.0)    viewFromTransform.m34 = const    viewToTransform.m34 = const    containerView.transform = CGAffineTransformMakeTranslation(direction * containerView.frame.size.width / 2.0, 0)    toView.layer.transform = viewToTransform    containerView.addSubview(toView)    UIView.animateWithDuration(transitionDuration(transitionContext), animations: {        containerView.transform = CGAffineTransformMakeTranslation(-direction * containerView.frame.size.width / 2.0, 0)        fromView.layer.transform = viewFromTransform        toView.layer.transform = CATransform3DIdentity    }, completion: {        finished in        containerView.transform = CGAffineTransformIdentity        fromView.layer.transform = CATransform3DIdentity        toView.layer.transform = CATransform3DIdentity        fromView.layer.anchorPoint = CGPointMake(0.5, 0.5)        toView.layer.anchorPoint = CGPointMake(0.5, 0.5)        if (transitionContext.transitionWasCancelled()) {            toView.removeFromSuperview()        } else {            fromView.removeFromSuperview()        }        transitionContext.completeTransition(!transitionContext.transitionWasCancelled())    })        }

Open ItemsTableViewController. swift and modify the class declaration as follows:

class ItemsTableViewController: UITableViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {

ByUINavigationControllerDelegateTo provide the animation controller.
Add the following attributes to the class.

let customNavigationAnimationController = CustomNavigationAnimationController()

Add the following code to viewDidLoad:

navigationController?.delegate = self

Add the following method to the class:

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {    customNavigationAnimationController.reverse = operation == .Pop    return customNavigationAnimationController}

Making it Interactive

IOS built-in apps have this feature

We need an interaction controller. Interaction controller uses the UIViewControllerInteractiveTransitioning protocol. Navigation controller delegate or transitioning delegate. After requesting an animation controller, requests also has an optional interaction controller.
To create an interaction controller. Create a new class named CustomInteractionController and inherit from UIPercentDrivenInteractiveTransition.
UIPercentDrivenInteractiveTransition implements the UIViewControllerInteractiveTransitioning protocol.
To use UIPercentDrivenInteractiveTransition, your animation controller must have a UIView animation so that the animation can be stopped, restored, and played.
Add the following code to this class:

var navigationController: UINavigationController!var shouldCompleteTransition = falsevar transitionInProgress = falsevar completionSeed: CGFloat {    return 1 - percentComplete}func attachToViewController(viewController: UIViewController) {    navigationController = viewController.navigationController    setupGestureRecognizer(viewController.view)}private func setupGestureRecognizer(view: UIView) {        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePanGesture:"))}func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {    let viewTranslation = gestureRecognizer.translationInView(gestureRecognizer.view!.superview!)    switch gestureRecognizer.state {    case .Began:        transitionInProgress = true        navigationController.popViewControllerAnimated(true)    case .Changed:        var const = CGFloat(fminf(fmaxf(Float(viewTranslation.x / 200.0), 0.0), 1.0))        shouldCompleteTransition = const > 0.5        updateInteractiveTransition(const)    case .Cancelled, .Ended:        transitionInProgress = false        if !shouldCompleteTransition || gestureRecognizer.state == .Cancelled {            cancelInteractiveTransition()        } else {            finishInteractiveTransition()        }    default:        println("Swift switch must be exhaustive, thus the default")    }}

Use interaction controller and add the following attributes to ItemsTableViewController. swift:

let customInteractionController = CustomInteractionController()

In navigationController (_: animationControllerForOperation:
FromViewController: toViewController :) method start position, add the following code:

if operation == .Push {    customInteractionController.attachToViewController(toVC)}

Then add the following method:

func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {    return customInteractionController.transitionInProgress ? customInteractionController : nil}

Download the completed project here

Other references:

  • How To Make A View Controller Transition Animation Like in the Ping App
  • CREATING A CUSTOM FLIP VIEW CONTROLLER TRANSITION
  • INTERACTIVE TRANSITIONS
  • IOS7 interactive transitions
  • Custom UIViewController Transitions

Another open-source tool is recommended to achieve slide return in projects:
Fdfullscreenpopgsture

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.