iOS: Hide rootViewController of SplitView in TabBar app - ios

I have a TabBar iPad app with a Split Controller in first tab. I follow this instructions to make it:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/62217-simplest-way-make-split-controller-tab-bar-controller.html
Now my goal is to hide the root view controller of the split controller. I found a method to accomplish this:
http://vimeo.com/13054813
But that doesn't works for me, because it only works assuming the split controller is in the MainWindow.xib. But with the previous method, the split controller is added programatically.
Can someone help me to get my goal? Any idea would be appreciated.
Thanks in advance!
Here are the code:
http://dl.dropbox.com/u/27695108/MariCruz.zip
I hope you can help me.
Thanks!

You have a couple of problems with your project.
1 First one is that you are using a UITabBarController, that is why the code you found to hide the root view controller does not work.
Second one lays with your implementation of makeSplitViewController, where you are initializing twice your splitViewController, rootViewController, and detailViewController.
So, you have to fix point 2, so that you can correctly manage all of those controllers and then you should modify toggleSplitView so that you take into account the fact that you are using a UITabBarController. For example, replace the first few lines of that method with the following ones:
- (void)toggleSplitView {
NSArray *controllers = _tabBarController.viewControllers;
UIViewController* controller = [controllers objectAtIndex:1];
if (controller.view == splitViewController.view) {
[splitViewController.view removeFromSuperview];
splitViewController.viewControllers = [NSArray arrayWithObjects:rootViewController, rootViewController, nil];
splitViewController.view = detailViewController.view;
} else {
....
As you say, I am no accessing _window to check if the UISplit is there, because that view is not under _window, rather it is in the tab bar. The other branch of the if also needs to be rewritten according to the same criteria, but I will leave it for you.
The above code will work only with your second tab (the one corresponding to index 1); indeed, since you are overwriting splitViewController in makeSplitViewController, I can only use the element at index 1 in the tab bar without making further changes.

Related

Reset current NavigationController and present another tab

I have an app (with a UITabBarController) that can reach the final payment view via two tabs, each with their own NavigationController.
(The illustration only shows the two tabs in question)
When payment is successful I want to reset both NavigationControllers and present tab 1.
If I was on tab 1 I could just use this code:
self.navigationController?.popToRootViewControllerAnimated(true)
But if I was on tab 2 that only brings me to the first viewController in navigationController in tab 2...
How can I present another tab while also resetting the NavigationController I am on (and others)?
Any help is very much appreciated. Thank you !
1) Create a custom UITabBarController or make a category that has a method called something like: completePayment()
- (void) completePayment
{
[self setSelectedIndex:n] // n is the index of your destination tab
[[[self viewControllers] objectAtIndex:m] popToRootViewControllerAnimated: YES]; // reset the stack in the current tab
}
2) trigger this method from the ViewController that the paymant is done as such:[self.tabbarController completePayment];
3) Profit!
There are probably ways of doing this in somewhat hacky ways, but what I will suggest you is that you reconsider your flow when you ask yourself a question like this one. Each UITab is designed to hold a UINavigationView that is self contained and independent from other UITab elements. If you force reset a tab that you are not on, you are breaking the flow and confusing the users.
So I recommend you push your Payment ViewController, wherever you need it in the app. And don't mess with other Tabs states.

Cant make navigation back to original tab without creating a new instance

Here is my set up in storyboard.
I'm trying to use this code: (In an IBAction connected to the UIBarButtonItem in the last VC):
- (IBAction)confirmClicked:(UIBarButtonItem *)sender
{
//EXECUTE NAVIGATION
UITabBarController * tabControl = [self.storyboard instantiateViewControllerWithIdentifier:#"TabBarControl"];
tabControl.selectedIndex = 1;
[self presentViewController:tabControl animated:YES completion:nil];
}
to navigate from the last ViewController in this picture to that very first UINavigationController in the stack. I was informed that UINavigationControllers are not meant to be nested like this, and that only one UINavigationController should be necessary, but when I successfully remove(which I have done at least 5 times) the other three UINavigationControllers from the rest of the stack, I completely lose my UINavigationBars from the regular ViewControllers.
The problem with navigating the way that I currently am with my 'confirmClicked:' method, is that I create another instance of that first UIViewController in the hierarchy.
Should I:
A) Remove all the unnecessary UINavigationControllera in the view hierarchy, then use 'popToRootViewController:' to correctly navigate from the last VC to the first?
B) Try to navigate another way from the last VC to the first VC, keeping the extra UINavigationControllers in the view hierarchy?
Also, if I remove the Navigation Controllers, how will I keep my navigation bars in the UIViewControllers, since they have been disappearing in the past when removing the Navigation Controllers?
Sorry in advance for the many questions but I have been stuck for a while.
OK
First thing
Remove all those navigation controllers. You only need one.
Second
The code in that IBAction is creating a brand new instance of the TabBarController and placing it over the current stack (this is how to get memory problems).
Third
What you probably want is either an unwind segue (possibly) or code something like this...
- (IBAction)confirmClicked:(UIBarButtonItem *)sender
{
//EXECUTE NAVIGATION
UITabBarController * tabControl = [self.tabBarController setSelectedIndex:1];
}

ios navigation Stack Manipulation

i am having issues try to manipulate the navigationstack from an ios app. Or at least with the behaviour as a result of that manipulation.
My Situation:
i have 3 ViewControllers.
Controller a shows multiple levels,
Controller b is the gameview
Controller c is some sort of Score
Obviously i will select a level in controller a, which triggers a segue to controller b, once the level is finished ill segue to controller c. every segue as a push.
Now once im in controller c i dont want to be able to go back to b using the back button. I want to move back to controller a. In order for this to work, i removed the controller from the stack, so back wont move to controller b. This works fine.
The issue im facing is that the backbutton does show on controller a, which seems off since there shouldn't be any back. If i click the backbutton, the app doesnt crash, the button just disappears leaving the title.
i tried adding :
NSArray* controllers = [self.navigationController viewControllers];
if ([controllers count]<=1) {
[self.navigationItem setHidesBackButton:YES animated:YES];
} else {
[self.navigationItem setHidesBackButton:NO animated:YES];
}
[super viewDidAppear:animated];
as suggested in some relative stackoverflow article, without success. Besides this not working it seems off that ios creates those buttons from Storyboard without me actually adding them, but doesnt remove them when they arent necessary anymore. This leaves me with some options.
either i think that ios is smarter than it actually is
i am missing something essential to update the navigationbar
i went at this all wrong
besdies im using this code snipped to segue from Controller b to c.
[self performSegueWithIdentifier:#"feedbackSegue" sender:self];
[self removeFromParentViewController];
Any hints concerning missing operations or general bad practice is greatly appreciated.
Update
After further investigation, its not just the back button, its the whole navigationbar that is off. it behaves as if the removed controller was still there. The BackButton is there and another uiActionButton on the right end.
Does the navigationbar store its states onto a different stack, than the viewcontroller one? if this was the case, i could remove that state from this stack as well, to keep it consistent.
You could try this in your view controller c. This will remove the previous view controller, in your case the b. You'd also have to keep b in your stack (remove the line [self removeFromParentViewController]'; )
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if(self.navigationController.viewControllers.count>2){
NSArray *controllers = self.navigationController.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray arrayWithArray:controllers];
[newViewControllers removeObject:[controllers objectAtIndex:self.navigationController.viewControllers.count - 2]];
self.navigationController.viewControllers = newViewControllers;
}
}
I believe the "correct" way to do this is to remove the back button on controller c. Depending on how and when you are removing controller b, you may be corrupting the navigation controller stack. It's generally not a good practice to manipulate the view controller stack.
To remove the back button, you have the correct code:
self.navigationItem.hidesBackButton = YES;
However, note that you must call this before the view controller is presented -- i.e., in something like viewDidLoad.
When you want to pop back to A, use:
[self.navigationController popToRootViewControllerAnimated:YES];

conditions for navigation between viewcontrollers

I am working with the project of ios and doing well in it. But now i stuck at one place where i am having three views (Say 1stview, 2ndview, 3rdview). I am navigating to second view from first view and third view using the code line below.
[self.navigationController pushViewController:first view animated:YES];
How can i check on second view wheather i am navigating from first view or third view. So that i can use particular condition on it.
So please help me out regarding this issue. Your help will be much appreciable.
Take a variable in second View controller. When you are creating the object of it, set proper value into it. Later on when it will get pushed, you can use that value to take proper decisions.
In the file of FirstViewController you will write below lines:
SecondController *controller = [[SecondController alloc]init];
controller.flag = 1; //That means you came here from viecontroller 1
[self.navigationController pushViewController:controller animated:YES];
In the file of ThirdViewcontroller you will write below lines:
SecondController *controller = [[SecondController alloc]init];
controller.flag = 3; //That means you came here from viecontroller 3
[self.navigationController pushViewController:controller animated:YES];
Try to arrange thing so that the 2ndView doesn't know about 1stView or 3rdView, but instead just changes it's behavior according to how it was configured. So, let's say that when you're navigating to 2ndView from 1stView, 2nd should display with a green background and when you get there from 3rd it should use blue instead. Rather than telling 2nd which controller preceded it, have the preceding controller just tell 2nd what background color to use. Same goes for any other aspect of 2ndView's behavior.
The benefit of doing it this way is that you can change 1st or 3rd without having to change anything in 2nd, and you can later add a 4thView or 5thView that also use 2ndView without having to change 2ndView.
Implement the method – navigationController:willShowViewController:animated: from the UINavigationControllerDelegate Protocol Reference. Inside this method you can check the navigation stack to get the current view controller using several properties of UINavigationController. An example would be access the visibleViewController property.
As #Apurv pointed out you need some sort of identifier mechanism to be able to know which view controller the call came from. e.g.: viewController.view.tag

Two tab bar items should show the same UIViewContoller

What I want is to have two UITabBarItems in my UITabBar (thats not really the problem...).
So normally the first item has his own an UIViewcontroller and the second item has his own UIViewcontroller.
But I want that each TabBarItem shows the same UIViewcontroller instance.
(the functionality is nearly the same, only one label is different between those two viewcontrollers)
So I think I have to push the last viewController on top of the tabBarItemStack right after the user pushed the second tabBarItem, right ?
At the moment I'm using a StoaryBoard with two UIViewcontroller, so I really don't know how I can access the TabBarItemStack and where do I get the notification that the next tab is pushed by the user ?
Or can I alter the stack after loading the first view and push the current view on the second index of the stack ?
Hope I was able to explain my problem so anybody would understand ;-)
Thanks and Regards,
I wouldn't use the UITabBar at all in this case. I would make some GUI-object in my viewcontroller that looks like two tabs, but is acually just 2 buttons.
When you click them you switch their look so that it looks like you have switched tabs, by changing the images of the buttons. But you are always staying in the same viewcontroller all the time. And you just change the content in it.
Then you can keep track class which "tab" the user has selected by using member variables and that way you know which content to show.
The UITabBar is most useful when you have an unknown amount of tabs and you don't know exactly what they will contain. There are many times it is a lot easier to not use the UITabBar and just images/buttons with "tab-looking" layout, even when you have more than one viewcontroller.
Could you have two UIViewControllers (one for each UITabBarItem), but they are both inherited (descended) from a third (Which contains all the logic). That way you are not duplicating the code, and not faffing with the hierarchy, such that you might introduce bugs?
Load same UIViewController in both TabBar. I assume u need to hide label in first tabBar and show in second tabBar
Now in viewWillAppear Method add this code:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(self.tabBarController.selectedIndex == 0)
{
yourLabel.hidden = YES;
}
else if(self.tabBarController.selectedIndex == 1)
{
yourLabel.hidden = NO;
}
}

Resources