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.
Related
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
I perform some data loading tasks from an Ojective§C class and once everything is loaded, I simply wants to display a Viewcontroller subclass prepared in a storyboard.
So when everything is ok, the following method is called:
- (void)loadingNextView
{
CABBndGSite *mySite = [CABBndGSite alloc];
CABBndGSelectLanguageViewController *vc = [[mySite myRootViewController].storyboard instantiateViewControllerWithIdentifier:#"SelectLanguageViewController"];
[[mySite myRootViewController] presentViewController:vc animated:YES completion:nil];
}
So I verified that myRootViewController is not nil. It's a UINavigationController class.
vc is not nil so it found my view in the storyboard.
Anyway, the presentViewcontroller message seems to doing what expected.
Certainly a stupid mistake but my poor iOS programming knowledge lets me in the fog!
I use this code from ViewController subclasses with success and as here I get a valid ViewController pointer, I don't understand why it doesn't work.
I also tried to implement the AppDelegate method explained here How to launch a ViewController from a Non ViewController class? but I get a nil navigation pointer. Maybe something not well connected in my application
May I have some explanation?
Kind regards,
UINavigationController maintains a stack of view controllers. You can access this stack through the viewControllers property. To present your view controller, you can:
(a) have the navigation controller push the new view controller on to
the stack (pushViewController:animated:);
(b) have the top view controller in the view controller stack present
the new view controller modally (presentViewController:animated:completion:), or;
(c) add the new view controller to the view controller stack array
manually by assigning a new viewControllers array to the navigation
controller's viewControllers property (setViewControllers:).
I'm starting to learn iOS development and am attempting to use UINavigationController as my window's root view. All is working well but I need some advice on how to structure my app. I read the docs and some questions on here too.
Since the navigation controller is managing all my other content view controllers, then all of these view controllers need a way to send messages to the navigation controller. Right? So, I've thought about making a singleton navigation controller that any other view controller can call on to push new view controllers on it. Or, if each view controller has a reference to the navigation controller then they can push/pop easily as well. This is the part I'm not sure about.
Also, for having buttons and actions I have been setting the target as the navigation controller and from there it can handle it correctly and push or pop on it's own. I did subclass UINavigationController for this. And I have my view controllers as references in it. However I ran into an issue where my UITableViewController was handling a selection of a row and I need to push a new view controller on top, but how do I get the reference to the navigation controller?
I hope that makes sense, and any advice on how to structure this would be very appreciated.
Thanks!
I think you're overthinking this. View controllers have a navigationController property built in allowing you to reference the navigation controller. That being said, pushing to a new view controller from within a view controller that is embedded in a navigation controller is as easy as:
UIViewController *myNewViewController = [[UIViewController alloc] init];
[self.navigationController pushViewController:myNewViewController animated:YES];
According to your requirement you need to write like this :-
UIViewController *myNewViewController =
[[[UIViewController alloc]
initWithNibName:#"yourNibName"]
bundle:nil]];
[self.navigationController
pushViewController:myNewViewController
animated:YES];
This will push one controller on the bottom of the stack.
I have a segue that navigates from FirstViewController to SecondViewController. This happens by the press of a button. The code for the button is
- (IBAction)segue:(id)sender {
[self performSegueWithIdentifier:#"myIdentifier" sender:self];
}
This happens correctly when i press the button.
What i am trying to do is fire this method from another view. I tried doing
FirstViewController fvc = [[FirstViewController alloc] init];
[fvc segue:nil];
When i try this, I get the error message, Reciever has no segue with identifier 'myIdentifier'
How do i fire this segue programatically from another view?
There are a few issues here, but they boil down to a couple of key points:
Segues are a storyboard thing, so view controllers only "know" about segues if they're instantiated from a storyboard.
A view controller must be onscreen to perform a segue.
Segues are transitions from one specific view controller to another specific view controller.
So, in your snippet:
FirstViewController fvc = [[FirstViewController alloc] init];
[fvc segue:nil];
The first problem is that alloc-init-ing gives you an instance of FirstViewController that doesn't know anything about the storyboard it came from, so it doesn't know anything about segues. (This alone could be fixed using [instantiateViewControllerWithIdentifier:][1], but that doesn't solve your whole problem.) A second problem is that this instance doesn't fit anywhere into the UI hierarchy -- it hasn't been presented as a modal view controller, it's not the top view controller in the current navigation controller, it's not the visible window's root view controller, etc. In order to transition the screen from one view to another, the first view needs to be onscreen.
What it sounds like you want to do is transition from what's currently onscreen to the target of this segue. But the notion of a storyboard segue isn't just a transition with a destination -- it's a source, a destination, and a transition or relationship between them. If you have a different source view, you need a different segue. So, if you already have a segue from FirstViewController to SecondViewController, and you want to make a similar transition from OtherViewController (assuming that's the one onscreen now) to SecondViewController, you need to make a second segue connecting OtherViewController to SecondViewController.
I'm running into trouble with what I think is a pretty basic task. Within peoplePickerNavigationController:peoplePicker:shouldContinueAfterSelectingPerson: i want to show my own view rather than the standard person view. I'm using a Storyboard, but don't think I can simply manually segue to a window here so I'm thinking I need to create a new XIB with a View Controller in it. I'm setting the Class of the View Controller to my custom View Controller in IB. Then in peoplePickerNavigationController:peoplePicker:shouldContinueAfterSelectingPerson: I'm doing:
MyVC *myVC = [[MyVc alloc] initWithNibName:#"XIBFileName" bundle:nil];
[self presentModalViewController:myVC animated:YES];
In my View Controller initWithNibName gets called, but not viewDidLoad. What am I doing wrong here?
Just try [peoplePickerVC presentModalViewController:myVC] instead of presenting from self.
The issue is that the peoplepickerviewcontroller will be in the top of the navigation stack. Becuase you wud've presented the peoplepicker from self. As this is the case, you wont be able to present/push from self as its not at the top of the navigation stack.
Otherwise once the peoplepicker has been poped, then you can further present from self.