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 chang
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()
}
}
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...
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