Change RootViewcontroller with the Push Transition effect
Asked Answered
S

3

7

in my iOS App i need to change the rootviewController of the window in between of app .so when i change my rootviewcontroller dyncamically its flicking the view before its change.but what i want is to give a smooth transition when rootviewcontroller is changed.

i had tried with the following but its not the transition i want.

[UIView transitionWithView:self.window
                      duration:.8
                       options:UIViewAnimationOptionTransitionCurlUp
                    animations:^{

                        self.window.rootViewController = tabBarControllerMain;
    [self.window makeKeyAndVisible];
                    }
                    completion:NULL];

i want specific transition like navigationcontroller pushview transition.

can any body give me idea how to achieve that?

Sigvard answered 23/6, 2014 at 9:51 Comment(0)
T
6

Based on this Apple's documentation

UIViewController *viewControllerToBeShown=[[UIViewController alloc]init];

//viewControllerToBeShown.view.frame = self.view.frame;

viewControllerToBeShown.view.backgroundColor = [UIColor orangeColor];



AppDelegateClass *yourAppDelegate  =(AppDelegateClass*)[UIApplication sharedApplication].delegate;


UIView *myView1 = yourAppDelegate.window.rootViewController.view;

UIView *myView2 = viewControllerToBeShown.view;

myView2.frame = yourAppDelegate.window.bounds;


[yourAppDelegate.window addSubview:myView2];


CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
transition.duration = 5.0;

// Add the transition animation to both layers
[myView1.layer addAnimation:transition forKey:@"transition"];
[myView2.layer addAnimation:transition forKey:@"transition"];

myView1.hidden = YES;
myView2.hidden = NO;


yourAppDelegate.window.rootViewController = viewControllerToBeShown;

Swift

        guard let appDelegate = UIApplication.shared.delegate,
            let appDelegateWindow = appDelegate.window,
            let appDelegateView = window.rootViewController?.view,
            let viewContollersView = viewController.view else {
            return
        }
        viewContollersView.frame = (appDelegateWindow?.bounds)!
        appDelegate.window??.addSubview(viewContollersView)
        let transition = CATransition()
        transition.startProgress = 0
        transition.endProgress = 1.0
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromRight
        transition.duration = 0.35
        appDelegateView.layer.add(transition, forKey: "transition")
        viewContollersView.layer.add(transition, forKey: "transition")
        appDelegateView.isHidden = true
        viewContollersView.isHidden = false
        appDelegateWindow?.rootViewController = viewController
Tagmemic answered 23/6, 2014 at 11:15 Comment(3)
This works however is there a way for the previous viewcontroller to not be black? The viewcontroller where I execute the code becomes black once the animation starts.Inlaw
In Swift, check this answer... its work https://mcmap.net/q/1399650/-change-rootviewcontroller-with-the-push-transition-effectScabble
This does not look as the transition in UINavigationController, you have to use a fake vcCherin
C
11

Basing on Hardik Darji's answer I've created UIWindow extension to swap rootViewController with configurable animation type that simulates system animations - push, pop, present and dismiss.

Swift 3.

public enum SwapRootVCAnimationType {
    case push
    case pop
    case present
    case dismiss
}


extension UIWindow {
public func swapRootViewControllerWithAnimation(newViewController:UIViewController, animationType:SwapRootVCAnimationType, completion: (() -> ())? = nil)
{
    guard let currentViewController = rootViewController else {
        return
    }
    
    let width = currentViewController.view.frame.size.width;
    let height = currentViewController.view.frame.size.height;
    
    var newVCStartAnimationFrame: CGRect?
    var currentVCEndAnimationFrame:CGRect?
    
    var newVCAnimated = true
    
    switch animationType
    {
    case .push:
        newVCStartAnimationFrame = CGRect(x: width, y: 0, width: width, height: height)
        currentVCEndAnimationFrame = CGRect(x: 0 - width/4, y: 0, width: width, height: height)
    case .pop:
        currentVCEndAnimationFrame = CGRect(x: width, y: 0, width: width, height: height)
        newVCStartAnimationFrame = CGRect(x: 0 - width/4, y: 0, width: width, height: height)
        newVCAnimated = false
    case .present:
        newVCStartAnimationFrame = CGRect(x: 0, y: height, width: width, height: height)
    case .dismiss:
        currentVCEndAnimationFrame = CGRect(x: 0, y: height, width: width, height: height)
        newVCAnimated = false
    }
    
    newViewController.view.frame = newVCStartAnimationFrame ?? CGRect(x: 0, y: 0, width: width, height: height)
    
    addSubview(newViewController.view)
    
    if !newVCAnimated {
        bringSubview(toFront: currentViewController.view)
    }
    
    UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut], animations: {
        if let currentVCEndAnimationFrame = currentVCEndAnimationFrame {
            currentViewController.view.frame = currentVCEndAnimationFrame
        }
        
        newViewController.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
    }, completion: { finish in
        self.rootViewController = newViewController
        completion?()
    })
    
    makeKeyAndVisible()
    }
}
Colubrine answered 18/4, 2017 at 13:50 Comment(3)
Perfect, but for Swift 3 recommends to use low register for cases in enumTurpin
I think I found small bug: viewWillAppear inside newViewController call twiceBriarroot
There is indeed a minor bug, it calls viewWillAppear and viewDidAppear twiceArthurarthurian
T
6

Based on this Apple's documentation

UIViewController *viewControllerToBeShown=[[UIViewController alloc]init];

//viewControllerToBeShown.view.frame = self.view.frame;

viewControllerToBeShown.view.backgroundColor = [UIColor orangeColor];



AppDelegateClass *yourAppDelegate  =(AppDelegateClass*)[UIApplication sharedApplication].delegate;


UIView *myView1 = yourAppDelegate.window.rootViewController.view;

UIView *myView2 = viewControllerToBeShown.view;

myView2.frame = yourAppDelegate.window.bounds;


[yourAppDelegate.window addSubview:myView2];


CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
transition.duration = 5.0;

// Add the transition animation to both layers
[myView1.layer addAnimation:transition forKey:@"transition"];
[myView2.layer addAnimation:transition forKey:@"transition"];

myView1.hidden = YES;
myView2.hidden = NO;


yourAppDelegate.window.rootViewController = viewControllerToBeShown;

Swift

        guard let appDelegate = UIApplication.shared.delegate,
            let appDelegateWindow = appDelegate.window,
            let appDelegateView = window.rootViewController?.view,
            let viewContollersView = viewController.view else {
            return
        }
        viewContollersView.frame = (appDelegateWindow?.bounds)!
        appDelegate.window??.addSubview(viewContollersView)
        let transition = CATransition()
        transition.startProgress = 0
        transition.endProgress = 1.0
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromRight
        transition.duration = 0.35
        appDelegateView.layer.add(transition, forKey: "transition")
        viewContollersView.layer.add(transition, forKey: "transition")
        appDelegateView.isHidden = true
        viewContollersView.isHidden = false
        appDelegateWindow?.rootViewController = viewController
Tagmemic answered 23/6, 2014 at 11:15 Comment(3)
This works however is there a way for the previous viewcontroller to not be black? The viewcontroller where I execute the code becomes black once the animation starts.Inlaw
In Swift, check this answer... its work https://mcmap.net/q/1399650/-change-rootviewcontroller-with-the-push-transition-effectScabble
This does not look as the transition in UINavigationController, you have to use a fake vcCherin
S
6

Here is code in Swift for how to make Push and Pop animation in rootviewcontroller.

//Declare enum
enum AnimationType{
        case ANIMATE_RIGHT
        case ANIMATE_LEFT
        case ANIMATE_UP
        case ANIMATE_DOWN
    }
// Create Function...

    func showViewControllerWith(newViewController:UIViewController, usingAnimation animationType:AnimationType)
{

    let currentViewController = UIApplication.sharedApplication().delegate?.window??.rootViewController
    let width = currentViewController?.view.frame.size.width;
    let height = currentViewController?.view.frame.size.height;

    var previousFrame:CGRect?
    var nextFrame:CGRect?

    switch animationType
    {
        case .ANIMATE_LEFT:
            previousFrame = CGRectMake(width!-1, 0.0, width!, height!)
            nextFrame = CGRectMake(-width!, 0.0, width!, height!);
        case .ANIMATE_RIGHT:
            previousFrame = CGRectMake(-width!+1, 0.0, width!, height!);
            nextFrame = CGRectMake(width!, 0.0, width!, height!);
        case .ANIMATE_UP:
            previousFrame = CGRectMake(0.0, height!-1, width!, height!);
            nextFrame = CGRectMake(0.0, -height!+1, width!, height!);
        case .ANIMATE_DOWN:
            previousFrame = CGRectMake(0.0, -height!+1, width!, height!);
            nextFrame = CGRectMake(0.0, height!-1, width!, height!);
    }

    newViewController.view.frame = previousFrame!
    UIApplication.sharedApplication().delegate?.window??.addSubview(newViewController.view)
    UIView.animateWithDuration(0.33,
        animations: { () -> Void in
        newViewController.view.frame = (currentViewController?.view.frame)!
            currentViewController?.view.frame = nextFrame!

        })
        { (fihish:Bool) -> Void in
            UIApplication.sharedApplication().delegate?.window??.rootViewController = newViewController
        }
}


// call the func for ANIMATE_LEFT or ANIMATE_RIGHT etc

     self.showViewControllerWith(rootViewController, usingAnimation: AnimationType.ANIMATE_LEFT)

Hope this helps...

Scabble answered 5/2, 2016 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.