I'm attempting to create an application that has a regular view shown on start-up. It acts as a introduction view with two buttons that give the user choices to sign or register. After clicking sign in I present the form with presentModalViewController. After they finish with this I want to dismiss the modal view, and swap the introduction view with a tab bar controller that is the regular application.
I'm having a lot of trouble getting this to happen animated though. I did manage to get the modal view to transition out with the new view below it, but then immediately the introduction view is reshown, and I'm not sure why.
In the delegate I'm running this:
[window addSubview:firstRunController.view];
Presenting the view is very standard
This is how i'm dismissing it and getting the behavior I said above:
QuestionMeAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[self dismissModalViewControllerAnimated:YES];
[delegate.firstRunController.view removeFromSuperview];
If you maintain views by navigationController, you can assign view controllers by - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated.
I did swap views by re-assigning view controllers of navigation controller first, and then call dismissModelViewController to leave current view controller or navigation view controller.
Related
I have an app with one main TabBarController containing two tabs that control two different views, A & B. View A is a scrollView and View B is a TableView. When i initially load the app, the scrollview in view A is empty.
In order to add pages to my scrollView, I have set it up as follows: I go to view B and perform one modal segue to a view embedded with a navigationBar. The navigationBar only has one button, 'Cancel', which I use to dismiss the view. Otherwise, the user must click on an image an perform another modal segue to a different view. This view has no navigation bar, and has one button 'DONE', which I use to perform a modal segue back to the initial tabBarController.
Here's the problem: the page is added to the scrollView with no errors after I press 'DONE'. However, I believe I now have two instances of the same tabBarController floating around in memory. When I attempt to grab the views contained in the scrollView with a different button, it tells me that it is now empty (even though it was full during viewDidLoad and viewDidAppear).
How can I remove the initial tabBarController view or otherwise how can I segue back to the tabBarController that I have already allocated? Any help would be extremely appreciated! Thanks!
You shouldn't do a segue back to the original view controller. Rather, you should dismiss the current view controllers animated, and show your original tabBarController.
Inside the view you were segueing back from, add:
tabBarController *tabs = (tabBarController*)[[self presentingViewController]presentingViewController];
tabs.selectedViewController = [tabz.viewControllers objectAtIndex:0];
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
Then you will have the view A appear and still use the same allocation.
I have a navigation controller that loads a tableview, from here the user can select a row which loads a detail view that gets pushed onto the stack. This detail view controller has a segmented control in the bottom bar which loads in a series of views using [self.view insertSubview:firstDetailViewController.view atIndex:0]; etc...
That works fine - one of the subviews loaded also contains a table which loads another detail view. This caused problems because I couldn't access the navigation controller from within the sub view. To do so I had to use:
YourAppDelegate *del = (YourAppDelegate *)[UIApplication sharedApplication].delegate;
[del.navigationController pushViewController:nextViewController animated:YES];
Which I found here: Accessing a Top Navigation Controller from a Subview Navigation Controller.
But there's another instance where similar functionality is required. From the home view controller a lists view is loaded and presented modally. From here I push 2 detail views onto this new navigation stack using self.navigationController etc... which works fine. But when the subview tries to push the detail view it doesn't work. self.navigationController doesn't work, the appDelegate one pushes them onto the other nav controller and self.parentViewController.navigationController doesnt work.
Any ideas?
So your Home VC does presentModalVC of a table view. The table view does a self.NavCon pushVC: detail. And the detail then fails to push a sub-detail. Is that the scenario?
I'm wondering where the tableview got it's nav controller from, since it was presented modally, which does not require a NavCon.
I'm also wondering if you could push the tableview onto the NavCon instead of presenting modally; then the detail should have an intact NavCon which could then in turn push a sub-detail.
Hope that helps.
-Mike
I currently have an application that does the the following:
S: Loads a view as a login screen to start with.
a: If login is successful I add a terms and conditions screen as a subview
b: If not successful I add a sign up form as a subview
F: Then I load the main part of my app on success of either of the a or b which is the part of the app where there is a navigation controller and a tab bar controller. This is set up in MainWindow.xib
S, a and b also have Nav bars but no navigation controllers as I didn't think I would need navigation control on the login screens.
However it turns out I do, I want to be able to have back navigation from both a and b to the initial login screen.
I have tried several ways of doing this including trying the following answers:
How to add navigation controller in View Based Application in iPhone?
How do you properly set up a secondary view to support a navigation Controller on the iPhone?
how to add navigation controller programatically?
But none of them work for me, they display the new Navigation controller over the login screen and dont load the a or b screens.
I'm guessing this is because I am adding them as subviews to my loginView and this is not the correct way to do this? My code is as follows:
if(self.tcSubViewController == nil){
TCSubViewController *_tcSubViewController = [[TCSubViewController alloc] initWithNibName:#"T&CView" bundle:[NSBundle mainBundle]];
self.tcSubViewController = _tcSubViewController;
[_tcSubViewController release];
}
[self.view addSubview:[tcSubViewController view]];
I'm guessing there's a fundamental flaw in the way my Login flows? I should be able to completely remove the LoginView and then display the Terms and conditions view without having to add it as subview, shouldn't I?
You need to dismiss the navigation controller to go back to.
To dismiss modal view:
1.Easy way: In your modal view in some method that you call to dismiss just add:
[self.navigationController dismissModalViewControllerAnimated:YES];
2.More complex way: Implement and delegate protocol on your modal view and make the view controller that presents the modal view the delegate of it. And in the delegate method dismiss the modal view. I do this way when I need to send data from modal view to the controller that present it.
Reference to this post
Navigation controller philosophy is that you add only navigationController.view as UIWindow subview and it wil manage the rest by itself. You only need to push/pop viewControllers and their corresponding views will be added/removed from screen automatically.
sample code from my current application:
HomeController *homeController = [[[HomeController alloc] init] autorelease];
self.controller = [[[UINavigationController alloc] initWithRootViewController:homeController] autorelease];
self.controller.navigationBarHidden = YES;
[self.window addSubview:self.controller.view];
[self.window makeKeyAndVisible];
and then to push next view you just add next controller:
[self.navigationController pushViewController:newController animated:YES];
I have an app which goes through a set of screens within a navigation controller, then there is a screen with a tab controller, which one of the contained views wants to display a modal view controller that should be displayed over the top of the whole app (not full screen though).
It's all working fine, but the modal window is partially covered at the top by the navigation controller. I've tried using self / self.tabBarController / self.navigationController / self.tabBarController.navigationController to call presentModalViewController but they either don't work or still display the modal window underneath.
I've been searching for an answer to this all day, everyone else seems to have problems when it DOES overlap, not when it doesn't.
Any ideas? Thanks. (code, screenshots & video below)
- (IBAction)add:(id)sender {
// create the view
AddAttainmentController *addScreen = [[AddAttainmentController alloc] init];
// pass in a selected pupil
[addScreen setPupils:[NSMutableArray arrayWithObject:pupil]];
// add the view to a navigation controller
UINavigationController *control = [[UINavigationController alloc] initWithRootViewController:addScreen];
// place the navigation controller on the screen
[self presentModalViewController:control animated:YES];
// release at the end
[control release];
[addScreen release];
}
Screenshots: http://cl.ly/032v2k0t0N1s1m3H0511 (you can see the navigation bar as the modal window slides in) http://cl.ly/1h0o453Y3Z051P3S1S37 (the navigation bar of the modal window is covered by the original)
Video: http://cl.ly/1e2J3o1q3V1l1j470m12
It sounds like you failed to consider some of the restrictions and assumptions around using Apple's view controller classes and are getting undefined and unexpected behavior as a result.
Tab bar controllers expect to always be at the root of your controller hierarchy. From the class reference:
When deploying a tab bar interface, you must install this view as the root of your window. Unlike other view controllers, a tab bar interface should never be installed as a child of another view controller
Additionally modal view controllers (and all view controllers for that matter) are assumed to fill their window.
I've been reading the Head First iPhone Development book and I understand how to get to a new view from a table but how exactly would I be able to get to a new view or view controller, by just simply pressing a button? Is that even possible?
I mean there are some apps where you click a button, not a table cell and it loads a new view. How exactly is that done? If someone could help out a newbie it would be greatly appreciated!
I think what you're looking for is a modal vew controller. THis presents a modal view like you described on top of everything else. If rootViewController is the view controller that is displaying your current view, and myNewViewController the view controller you want to display modally:
[rootViewController presentModalViewController:myNewViewController animated:YES];
There's plenty of examples of this kind of thing on the net, just search for presentModalViewController
Like bpapa said in the comments, it's hard to be specific without code. However, generally what you want to do is:
Build a navigation controller that contains one original view.
Create a button in your original view using the Interface Builder.
Build a callback method (usually defined with IBAction) that is run when the button is pushed.
In that callback method, create a new view and push it onto the navigation controller the same way you would using a table view cell.
Alternately, if you only want one level of hierarchy, you could use a modal view controller; instead of pushing onto the navigation controller in the last step, just present the modal view controller.
The general answer is that you have an object that manages which view controller loads when.
The most commonly used is the UINavigationController. It is a UIViewController that instead of controlling views, controls other view controllers. It works like a simple stack. You push views you want to display onto the nav's controller stack and when you want them to disappear you pop them off.
A common (though sloppy) way of using a nav is to make it a property of your app delegate. Then anywhere in your app you can references it by:
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
The view controller for the first the user sees is held in the nav's topViewController property. If you want to load a view based on a user action in the topViewController.view, you would have something like this:
- (IBAction) loadNextView:(id) sender{ // Action called by a a UI event such as a button press.
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
UIViewController *nextViewController=...// load from nib, connect with IBOutlet, create programmatically
[nav pushViewController:nextView animated:YES];
}
The first view disappears to be replaced by the next one. To return to the first view, you have a method in the next view controller like so:
- (IBAction) unloadSelf:(id) sender{ // Action called by a a UI event such as a button press.
UINavigationController *nav=[[[UIApplication sharedApplication] delegate] navigationController];
[nav popViewControllerAnimated:YES];
}
... and the nav returns you automatically to the previous view regardless of what that view was.
When you first start out, especially if you use Interface Builder, the structure of the app is largely hidden. Behind the scenes all view controllers and their views exist in a hierarchy of some kind that leads back up to the app delegate. You should train yourself to think in hierarchal terms even if it is not immediately obvious how that hierarchy is constructed.