iOS switch rootViewController not working - ios

I have a login view that checks to see if there are default settings, then syncs data. If there are no default settings, the view waits for the user to login. if there are settings and the data syncs correctly, it should switch to my split view.
The code works if the user enters their login information. It syncs the data, then switches the view. If the user is already logged in, it hits the function and doesnt switch the view.
Here is the code being called by both paths:
-(void)redirect{
NSLog(#"Redirect#");
UISplitViewController *split = [self.storyboard instantiateViewControllerWithIdentifier:#"orders_split"];
[self.view.window setRootViewController:split];
}
"Redirect#" shows in the log on the initial load if the user has already logged in once. I have confirmed that there are no sync errors, it hits the function but does not perform the switch.
I am moving from a standard view with nav controller to a splitview, so I cannot use a manual segue trigger.

try to use app delegate:
UISplitViewController *split = [self.storyboard instantiateViewControllerWithIdentifier:#"orders_split"];
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = split;
in my projects I do it with animation:
+(void)setRootController:(UIViewController*)controller
storyboard:(UIStoryboard*)storyboard{
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[UIView
transitionWithView:appDelegate.window
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^(void) {
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
appDelegate.window.rootViewController = controller;
[UIView setAnimationsEnabled:oldState];
}
completion:nil];
}

Related

iOS Changing rootViewController after login / logout process in Objective-C

I've read many question about this issue but I don't figure out what it doesn't work.
Basically I want to change my root controller after the user logged in the or logout from the app. I am also using the storyboard.
My problem is SILoginViewController dealloc's function is never called, in this controller I send Notification and the observer is not removed, so it mess up everything, and after several "login/logout" it receives several notifications.
My AppDelegate :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.window setFrame:[[UIScreen mainScreen] bounds]];
BOOL isLoggedIn = [[SIUser aUser] isLoggedIn]; // from your server response
NSString *storyboardId = isLoggedIn ? #"rootViewController" : #"navVcForLogin";
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardId];
return YES;
}
If the user was not logged in and he success the process a Notification is send, here is the handler where I want to change the rootViewController :
- (void)loginSuccessHandler:(id)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
SIRootViewController * vc = [sb instantiateViewControllerWithIdentifier:#"rootViewController"];
[UIApplication sharedApplication].keyWindow.rootViewController = vc;
}
This is the same process for the logout, and here is the notification's handler :
- (void)logoutHandler:(id)sender
{
UIWindow *myWindow = [(SIAppDelegate *)[[UIApplication sharedApplication] delegate] window];
SILoginViewController * vc = [sb instantiateViewControllerWithIdentifier:#"navVcForLogin"];
[UIApplication sharedApplication].keyWindow.rootViewController = vc;
}
The easiest is to show you directly the storyboard :
The implementation in the Storyboard could seems weird but I'm using https://github.com/romaonthego/RESideMenu
I followed their storyboard implementation.
The thing is the SILoginViewController dealloc's method is never called.
But by the way it is working fine, in appearance I mean, when I run the application the behaviour is the good one, but It is sure it will mess out later on.
UPDATE
And I guess it is the common behaviour but there is no transition when the root view controller is changed and there is a black screen for a really short time when the new controller is appearing.
Black screen resolved using : in my AppDelegate.m
- (void)changeRootViewController:(UIViewController*)newRootViewController
{
if (!self.window.rootViewController) {
self.window.rootViewController = newRootViewController;
return;
}
UIView *snapShot = [self.window snapshotViewAfterScreenUpdates:YES];
[newRootViewController.view addSubview:snapShot];
self.window.rootViewController = newRootViewController;
[UIView animateWithDuration:0.3 animations:^{
snapShot.layer.opacity = 0;
snapShot.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
} completion:^(BOOL finished) {
[snapShot removeFromSuperview];
}];
}
RootViewController Switch Transition Animation
This probably kind of a duplicate question but I spent hours to figure out this problem.
[currentRootViewController willMoveToParentViewController:nil]; // notify the VC of movements
[self addChildViewController:newRootViewController]; //Add the new VC
[self transitionFromViewController: currentRootViewController toViewController: newRootViewController
duration: 0.15 options:UIViewAnimationOptionCurveEaseInOut
animations:^{
newRootViewController.view.frame = currentRootViewController.view.frame;
}
completion:^(BOOL finished) { //Cleanup from the move
[currentRootViewController removeFromParentViewController];
[newRootViewController didMoveToParentViewController:self];
}];
The code for willMoveToParentViewController and didMoveToParentViewController will notify the ViewController of the changes, and should get your dealloc called, since there is now nothing holding onto the ViewController, unless you have a pointer to it somewhere, then you will need to nullify all your pointers to the code. The solution you tried is only half of what needs to go on to get the transition completed successfully.

A memory warning when replacing a root viewController with animation

I could see that when i am replacing the root viewController without animation, everything works great, but when i am adding animation to it , its of course looks better, but it gives me a memory warning at the moment of the transition .
I am using iPad Air , I guess its because at that moment there are 2 views in the stack ??
Should i ignore it, or there is anything i can do ?
UIViewController *mainV=[self.storyboard instantiateViewControllerWithIdentifier:#"mainView"];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[UIView transitionFromView:delegate.window.rootViewController.view
toView:mainV.view
duration:0.75f
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished)
{
delegate.window.rootViewController=mainV;
}];
Placed your code in the dispatch_asynch and check:-
UIViewController *mainV=[self.storyboard instantiateViewControllerWithIdentifier:#"mainView"];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[UIView transitionFromView:delegate.window.rootViewController.view
toView:mainV.view
duration:0.75f
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished)
{
dispatch_async(dispatch_get_main_queue(), ^{
delegate.window.rootViewController=mainV;
});
}];
});

how to show and hide UISplitViewController with animation

The current rootViewController of window in my app is MainViewController. and there's a button in another view controller called SubViewController, I want to show UISplitViewController if a user click the button. I have implemented it as following:
//SubViewController.m
UISplitViewController *splitVC =[self splitVC];
self.view.window.rootViewController = splitVC;
there's no animation to show splitVC, I need to show it with slide style, example, to slide the SubViewController.view to right to show the UISplitViewController, and if the user click a button on UISplitViewController, to slide back the SubViewController.view
Try it this way:
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
UISplitViewController *splitVC =[self splitVC];
[UIView transitionWithView:self.view.window
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
appDelegate.window.rootViewController = splitVC;
}
completion:^(BOOL finished){
}];
You can specify different animation types with the options parameter

Switch between two UIWindows

I am integrating Pushwoosh SDK for Push Notification, which is using UIWindow to represent HTML page sent from Pushwoosh portal
- (void) showWebView {
self.richPushWindow.alpha = 0.0f;
self.richPushWindow.windowLevel = UIWindowLevelStatusBar + 1.0f;
self.richPushWindow.hidden = NO;
self.richPushWindow.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView animateWithDuration:0.3 animations:^{
self.richPushWindow.transform = CGAffineTransformIdentity;
self.richPushWindow.alpha = 1.0f;
} completion:^(BOOL finished) {
}];
}
- (void) showPushPage:(NSString *)pageId {
NSString *url = [NSString stringWithFormat:kServiceHtmlContentFormatUrl, pageId];
HtmlWebViewController *vc = [[HtmlWebViewController alloc] initWithURLString:url];
vc.delegate = self;
vc.supportedOrientations = supportedOrientations;
self.richPushWindow.rootViewController = vc;
[vc view];
}
And on closing on HTML page it calls
self.richPushWindow.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.richPushWindow.transform = CGAffineTransformMakeScale(0.01, 0.01);
self.richPushWindow.alpha = 0.0f;
} completion:^(BOOL finished) {
AppDelegate * appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
self.richPushWindow.hidden = YES;
}];
Now I want to call my view controller on closing of this HTML page. So I tried to present myviewcotrlller in this block completion but not presenting.
Actually here problem is that there are two UIWindows in my app one of app and other used by sdk. Now if i try to present view controller from this html page which is on separate UIWindow so it creates a separate hierarchy and when i close this window also removes my presented viewconroller due to parent-child relationship. And if do not close this window then how to come back to actual flow of app.
I want that new controller should be presented from that new window and after that window should be close and flow of app should not be affected by additional window. Is it possible? If my concept is wrong, Please help if anyone has idea
Edit: second uiwindow never be key window, it only becomes visible by setting higher windowlevel and become hidden
The problem is that right after this completion block richPushWindow will be gone, effectively this means you are trying to present view controller on a hidden window.
The solution is very simple. Use main window to present view controller. Some pseudocode:
Add view from the ViewContoller to the main window subviews:
[appDelegate.window addSubview:myViewController.view];
Modal:
[appDelegate.window.rootViewController presentModalViewController:myViewController]
Using View Controller hierarchy:
Push your viewController to the main viewController stack. For example if you have navigationController, just push it there.
I hope it helps!

Present multiple Images in fullscreen

I'm looking for the name of the class Apple uses to present a number of Images in full screen (similar to the AppStore-App on iPad when you tap the preview images of any App. In the bottom of the view is a bar with little preview Images from all the Images).
If this is a public class, how is it called and is it available for iPhone as well?
Ok so I have created my own ImageFullScreenPresenter.
What is important for anybody trying to build their own ImageFullScreenPresenter is to make it a subclass of UIViewController.
PKImageFullScreenPresenter *pkImageFullScreen = [[[PKImageFullScreenPresenter alloc] initWithNibName:#"PKImageFullScreenPresenter" bundle:nil imageArray:myImageArray] autorelease];
AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
UIViewController *rootViewController;
if (DEVICE_IS_IPAD) {
//since the splitviewcontroller is the rootviewcontroller on ipad i set it as my temporary rootViewcontroller for ipad
rootViewController = appDel.splitViewController;
}
if (DEVICE_IS_IPHONE) {
//on iphone i need the tabbarcontroller as temporary rootviewcontroller
rootViewController = appDel.tabBarController;
}
//set the alpha to zero, so it can fade in animated
pkImageFullScreen.view.alpha = 0;
//save the temporary rootViewController, so I can set it back when dissmissing the ImageViewController
pkImageFullScreen.superViewController = rootViewController;
//hide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
//setting black backgroundcolor
[UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor blackColor];
//init the fullscreencontroller as rootview
[[UIApplication sharedApplication].keyWindow setRootViewController:[[[UINavigationController alloc] initWithRootViewController:pkImageFullScreen] autorelease]];
//smooth fade animation
[UIView animateWithDuration:.5f
animations:^(void){
pkImageFullScreen.view.alpha = 1;
}];
Doing so, allows me to present the ImageFullScreenPresenter on iPhone and iPad, no matter you are using a window-based app, a splitViewController on iPad or whatever.
When dismissing the ImageFullScreenPresenter i set the temporary saved rootViewController back with an animation:
- (void)closeView:(id)sender{
[UIView animateWithDuration:.5f
animations:^(void){
self.view.alpha = 0;
}completion:^(BOOL finished){
//show the statusbar again
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
//setting the statusbarstyle
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];
//set the backgroundcolor for the window
[UIApplication sharedApplication].keyWindow.backgroundColor = GLOBAL_TINT_COLOR; //my custom color vor all GUI Objects
//set the temporary rootViewController back
[[UIApplication sharedApplication].keyWindow setRootViewController:superViewController];
//sometimes the navigationbar hides the statusbar, the following two lines help me out
[[UIApplication sharedApplication].keyWindow.rootViewController.navigationController setNavigationBarHidden:YES];
[[UIApplication sharedApplication].keyWindow.rootViewController.navigationController setNavigationBarHidden:NO];
}];
}
I dont know if this is the right way to go, but it works perfectly finefor me. I do not have to worry abput any rotation issues like I would have when i directly add this to [UIApplication sharedApplication].keyWindow.
I hope this helps others who try do achieve the same :)

Resources