Start second view controller of navigation stack first - ios

There is a default calendar app.
It starts with the next view controller and back button is already there like there some other view controller was started before this one:
When you press back button you get the next view controller:
How did they do it?
In my app I need the same logic (to start a view controller with the latest or default category but users can press back button to select a different category)

If I were to do this, I would start by simply using pushViewController(animated:) to push the month view onto the navigation stack, with animated: false in the root view controller's viewWillAppear(animated:) method. The calendar would appear to the user already one level deep in the navigation stack.
So, the first controller is the year view, and then the month view is the second one pushed onto the stack, but it all happens before the user has seen any of the views. Simple, right?
Here are the docs for UINavigationController in case that helps.

I think what you want is to push the view controllers once at start. An easy way to do it is to sub-class UINavigationController and assign it to the root navigation controller in your storyboard. Then simply do the work in your sub-class' viewWillAppear method, as this will be called exactly once at startup.
Of course, you can also accomplish the same result by using a flag to only load the next view controller once if you put the push code in the first view controller's viewWillAppear.
#interface MyNavigationController : UINavigationController
#end
#implementation MyNavigationController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIViewController *secondVC = [self.storyboard instantiateViewControllerWithIdentifier:#"secondVC"];
[self pushViewController:secondVC animated:NO];
}
#end

Related

ContainerView childViewControlllers view frame taking whole screen

Please see the following attached image for more understanding.
The scenario is : I have five view controllers
Each view navigate to next viewController on push
Now the MidContainerViewController has got the Container which embeds the FirstViewController.
Bottom of MidContainerViewController is a static view which should not change while navigating further.
On navigation The FirstViewController should be of size equal to container
Also when I navigate to SecondViewController from FirstViewController, it should also be of size of Container.
Objective 1 : 'FirstViewController' and 'SecondViewController' should not take whole screen overlapping the bottomView image on MidContainerViewController.
Objective 2 : I must pop to root "View Controller" on last 'push' on SecondViewController.
Solutions :
1) Currently As I have embedding the root "View Controller" to navigationController. No problem with objective 2. It successfully navigates back to root. But can't achieve objective 1
2) If I embed the "First View Controller" too with navigationController the objective 1 is achieved but start facing problem for objective 2. It pop back till 'MidContainerViewController' only.
Any suggestion are highly appreciated.
Thanks,
Assuming your are manually handling push/pop events without using storyboard, I recommend you to not push the FirstViewController from MidContainerViewController. Add the next view controller as child view controller through following code:
FirstViewController *firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:[NSBundle mainBundle]];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[self addChildViewController:navController];
[navController.view setFrame:CGRectMake(0.0f, 0.0f, _containerView.frame.size.width, _containerView.frame.size.height)];
[_containerView addSubview:navController.view];
[navController didMoveToParentViewController:self];
From the above code you'll achieve your first objective. In the above code, the FirstViewController gets initiated on its own separate navigation controller object, so it will have different navigation stack. So if you further push and pop from FirstViewController & SecondViewController, your view will not take the whole screen. But if you call popToRootViewController from last view controller, your root view controller would be FirstViewController in that specific container view.
To achieve second objective, you'll have to create a public property to contain reference of main navigation controller object in your AppDelegate class. Create your root view controller from that navigation controller object. In your last view controller, you'll then have to get reference of that navigation controller property from your AppDelagate class and then call popToRootViewController from that object.
i think you must present your root view controller from the secondView Controller rather that embedding to root view controller.
Thank you everyone.
The problem is solved and both the objectives are achieved.
I kept only one navigation controller as root view controller.
I created one customContainerViewController.
This class has instances of all the children it is supposed to show.
This class acts as delegate for each of its childViewController. Make customContainerViewController as deleagte of each childViewController.
I updated the chilren using delegation method and using UIView transition method in UIKit.
This worked for me.

Change ViewController

I have a multi-player game where I want it to start after I press a button in the menu. The problem is I don't know how to transit from the menu to the game directly after I start multiplayer.
In ViewController.m
- (IBAction)multiplayer:(id)sender {
[Nextpeer launchDashboard];
}
In AppDelegate.m
-(void)nextpeerDidTournamentStartWithDetails:(NPTournamentStartDataContainer *)tournamentContainer {
UIStoryboard *storyboard = self.storyboard;
ArcadeView *svc = [storyboard instantiateViewControllerWithIdentifier:#"arcade"];
[self presentViewController:svc animated:YES completion:nil];
srandom(tournamentContainer.tournamentRandomSeed);
[tournamentContainer tournamentIsGameControlled];
}
I'm getting the error of
"Property'storyboard'not found on object of type 'AppDelegate *' and
"No visible #interface for 'AppDelegate' declares the selector
'presentViewController:animated:completion:'"
How do I change from one ViewController to another ViewController using storyboard?
Normally in cocos2d, I would do like this:
CCScene *gameplayScene = [CCBReader loadAsScene:#"GamePlay"];
[[CCDirector sharedDirector] replaceScene:gameplayScene];
What's the equivalent?
How do i change from one ViewController to another ViewController using storyboard?
Typically, you'd use a segue to switch from one view controller to another. You can create a segue in your storyboard, connect it to a button, and the button will automatically trigger the segue and transition to the next view controller. As part of the segue process, the existing view controller will get a chance to "prepare" for the segue, at which point it can clean up after itself as necessary and also provide any information that the next view controller might need. Read all about it in the docs for -[UIViewController prepareForSegue:sender:].
There are a number of different ways that you can transition from one view controller to another, of course. You can push a new view controller onto a navigation stack, have a tab bar controller switch between several view controllers, present a view controller, simply remove one view controller's view hierarchy from the window and install the new one, and so on. Many of the possible transitions are provided by existing segue types, but you can also create your own custom transitions by creating your own segues.
If all this is new to you, you should probably spend some time reading through View Controller Programming Guide for iOS.

Uncertainty with instances in navigation: UITabBarController

In my app, I have a UITabBarController that is set as the initial view controller and has the storyboard ID 'TabBarControl'. TabBarControl has 4 tabs, and off of the second tab(index 1) there is a sequence of UIViewController navigations that goes as such, where VC is ViewController..
UITabBarController > UINavigationController('branchesControl') > VC1('branchesView') > UINavigationController > VC2 > UINavigationController > VC3 > UINavigationController > VC4
I have a UIBarButtonItem named 'Confirm' on the navigation bar in VC4. The Confirm button triggers the following IBAction method:
- (IBAction)confirmClicked:(UIBarButtonItem *)sender
{
//EXECUTE NAVIGATION
UITabBarController * tabControl = [self.storyboard instantiateViewControllerWithIdentifier:#"TabBarControl"];
tabControl.selectedIndex = 1;
[self presentViewController:tabControl animated:YES completion:nil];
}
The goal is to navigate from VC4 back to the original 'branchesView'
The problem is, I've noticed that a manual set of a color of a UIBarButtonItem on VC2's navbar resets to a default white after hitting Confirm and then revisiting the view stack. I believe that I am creating multiple instances.
How can I simply navigate back to branchesView, and then VC2 without creating new instances?
PS I'm not sure if the new instance is TabBarController or or branchesView, I just know that it would seem that I am creating multiple instances somehow with the confirmClicked: method.
Instead of going back to the existing branchesView, you are presenting a new UITabBarController with a whole new set of child view controllers which is almost certainly not what you want to be doing.
Instead, you need to pop back to the already existing view controller that you want to get back to. You can do this either by reference or index, and in your case, by simply popping to the root (provided the view controller you want to get to is indeed at the root).
You can simply do:
[self.navigationController popToRootViewControllerAnimated:YES];
Your question also makes it seem like each view controller in the stack is wrapped in a new navigation controller. if that is the case, you will need to fix that as well. You should not nest UINavigationControllers. Instead, have a single one as the root for each tab and each time you want to push a new UIViewController onto the stack, you call:
[self.navigationController pushViewController:viewControllerToPush animated:YES];

How do I emulate 'Notes' from Apple and start the app with a navigation controller with a 'back' view?

I have an application that has a login page. It then moves to a navigation controller that has a collection view as its root view controller. When the app starts and there is only one item in the collection, I want to have the navigation controller automatically push to that item and allow the user to use 'back' to view the collection. This is the same behavior that is in 'Notes' from Apple.
The idea is to allow the user to immediately start to use the app and only 'discover' the need for the collection view after using the app for some time.
I am using IB, storyboards, and segues for my view transitions.
If I programmatically have the root view controller do a performSegue in its viewWillLoad: I get an error about causing a transition while a transition is still in process.
If I move the code calling performSegue into the didLoad, then the user sees a double transition.
A navigation controller usually manages the underlying stack itself. That is, you pass it an initial view controller, and then through segues or pushViewController:animated: the stack is altered. However, there is nothing stopping you from manually altering the stack. In prepareForSegue:sender:, you can check the number of items, and if it's 1, do something like this:
UIViewController *singleItemViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"SingleItem"];
NSMutableArray *viewControllers = [sender.destinationViewController.viewControllers mutableCopy];
[viewControllers addObject:singleItemViewController];
sender.destinationViewController.viewControllers = viewControllers;
Now instead of starting at the first view controller of the stack, you start at the second one, with a back button to navigate back.
Actually, I found that the following worked the best for me.
if (/* reason to change back list*/) {
UIViewController * rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"backViewController"];
NSArray * viewControllers = #[rootViewController, self];
[self.navigationController setViewControllers:viewControllers animated:NO];
}
setViewControllers seems to be the best way to manipulate the stack.

Navigate to Root ViewController From Modal

I have a root view controller (RVC) that opens up a Modal ViewController (MVC). I then navigate within the MVC to few more VC's via a push. What is the best practice to get from one of those VC's back to the RVC?
Normally I have a delegate from the Modal VC that calls up to the RVC which then dismisses the modal, but if you navigate away from it, but I'm not sure how I would do that if you navigate away from it.
Without seeing any code it is a bit hard to help but let me shoot in the dark here.
I will assume that the first controller presented inside the modal view provides the protocol/delegate to call the dismiss action.
If you use UINavigationController inside your modal view to push other view controllers on the stack you can always obtain the first controller like this
UIViewController * yourFirstController = [[[self navigationController] viewControllers] objectAtIndex:0];
// and then use your delegate to call your dismiss method
// you will need to typecast your controller based on your subclass otherwise will get warning here
if ([[yourFirstController delegate] respondsToSelector:#selector(yourCloseProtocolMethod)]) {
[[yourFirstController delegate] yourCloseProtocolMethod];
}
Don't forget that a delegate doesn't have to be a property of a UIViewController inside your model navigation stack. Consider creating a singleton class that holds a reference to the rootviewcontroller as a delegate. That way any class in your application has access to it and you aren't forced to continually pass it through to every UIViewController that requires it.

Resources