I have this ad class which contains an UIImageView. I've added an instance of the class to my appdelegate onto the "window" view.
Now, I want to, when the user taps the ad, push my "detailedViewController" onto the current navigation controller, which all of my tab bar items contain. I don't know if it is possible.
Perhaps, I should just add my advertisement class to every view controller for every nav controller. However, if the user pushes or changes a view controller it would reset the class.
I just want to overlay the ad once.
EDIT:
Let me rephrase, can I from the app delegate and from my object know which tab bar item is selected? If I can determine which tab bar item is selected I can point to the appropriate nav controller instance.
The easyiest way would be to present your DetailVC as a ModalView which also makes sense in semantics.
Yes, it is possible to detect which tab is selected but it is easier to use the selectedViewController-property of UITabBarController.
UIViewController *curVC = myTabBarController.selectedViewController;
if([curVC isKindOfClass:UINavigationController.class])
{
UINavigationController *nav = (UINavigationController*)curVC;
[nav push...];
}
else
{
// do sth else: go to webpage for instance
}
Whoever owns the tab bar controller can do
[myTabBarController selectedIndex];
or
[myTabBarController selectedViewController];
The first one returns the index of the selected item, the second one the actual view controller, you might be better off with the first one.
Related
I have a tabbar-based application (tabbar controller is added in window itself) and all the navigation controller with their respective root view controllers are being set in window's xib. I have 4 tab bar items.
Suppose I click on item 1, then the root view controller for that item is being shown to me. This root view contains a table with 5 cells. If I click on a row, then a new view is pushed onto the navigation stack. Now, this pushed view has a button clicking on which will again push a new view controller. I have 4 such view controllers which are getting pushed one after the other on navigation stack.
Now, lets say I am on 3rd view in navigation stack and then, I have clicked on tab bar item 1 (the same on which I clicked earlier); then, the first root view controller is shown and my whole navigation stack is gone. I just don't want this to happen, that is, I want to remain on the 3rd view controller and also, be able to click on all tab bar items (dont want to disable any item). I know that it can be achieved through implementing tab bar controllers delegate method: shouldSelectViewController, but i dont know how??
perform a check for the currently selected viewcontroller.
if current is the same as the tab tapped, then return no in your delegate method. Think something like this is what you mean?
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;
{
if ([[tabBarController viewControllers] objectAtIndex:tabBarController.selectedIndex] == viewController)
{
return NO;
}
else
{
return YES;
}
}
I have an iPhone / iPad application that manages its numerous view controllers via a UINavigationController and UITabViewController. The UINavigationController handles the majority of the user interaction and the UITabViewController handles user settings/preferences.
My app delegate initializes the UINavigationController and pushes the first view controller. Settings (the UITabViewController) can be accessed via a button on the navigation controller's menu bar; the user can return to the main application (the UINavigationController) via a button on the UITabViewController.
My question is: what should I be doing with the UINavigationController (and its stack of view controllers) when I show the UITabViewController and vice-versa? Is there any reason to remove/release/recreate each parent controller as the user switches between the two, or should I be adding/removing each parent controller's view to my app's window?
It seems that the first option would be more mindful of memory/resources, however these benefits might get overshadowed by the processing cost to re-alloc/init the view controllers each time.
Thanks.
You do not have to manage the navigation controller's stack manually. What I would do is present your settings view controller as a modal view. You would do this at the navigation controller level.
Assume that settingsViewController is a property of your main view controller.
self.settingsViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal
[self.navigationController presentModalViewController:self.settingsViewController animated:YES];
I assume you mean UITabBarController.
If your navigation view would show up in the tab view for a tab item, I would suggest let the tab bar controller to be the root view controller of your application (and therefore always seen in the app).
If your navigation view is the main view, and the user simply opens up the tab bar view for settings etc. and will return for the navigation view, then modally presenting the tab bar controller is the right way.
In the first case (the navigation controller IN the tab bar controller), you would not care for adding/removing or allocating/releasing views as the UIKit will manage it for you.
In the second case you may create a tab bar controller when you want to show it. presentModalViewController will retain the view controller so you can release it immediately after you send the message. If you want to hold the view controller then you create one when the application is loaded and retain it in the navigation controller (and the navigation controller will always remain in the memory).
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.
Let's have an example.
In application I have a tab bar controller.
Tab bar has two items dynamically - two view controllers.
User can select any of tab.
Suppose user selects first tab.
First view controller is already loaded.
Now he clicks on a button of First view controller.
From First View controller -> Second View controller is pushed.
Now when user taps on tab bar first item
second view is popped out.
This is done through by default by tab bar controller.
Now, If I want to check following condition
if(tab bar first item-view controller has first view controller view)
then perform this
if(tab bar first item-view controller has second view controller view)
then perform this
How to implement this logic?
If you are using a UITabBarController, you can use its selectedViewController property to know what kind of view controller is on the screen, so if you have two subclasses of view controller FirstViewController and SecondViewController you can say
if([[tabBarController.selectedVIewController isKindOfClass:[FirstViewController class]])
//... do something
else ...
I'm trying to get multiple levels of hierarchy working
with Navigation Controllers. I have 3 levels of hierarchy and
I can move down through the levels of hierarchy, but I can
only go back one level and not two levels, back to the starting
view.
I start by creating a navigation controller for View #1 and push the next
view, View #2, onto it. Then I add the navigation controller to the
subview of the window in didSelectRowAtIndexPath. Clicking on
a table row in View #1 , takes me to the next hiearchy level View #2.
This next hiearchy level view is also a table view. Here is where
I think the problem occurs. I create another navigation controller
and push View #3 onto it in didSelectRowAtIndexPath in the View
Controller for View #2. Clicking on a table row in View #2 takes
me to View #3. But when I use the back button to go back to View #2,
I go back to an empty view, and not the real View #2.
Do I only need one navigation controller to handle 3 levels of
hiearchy instead of two navigation controllers?
If #1 is yes, then how do I pass the navigation controller to view #2's
controller so that I can push View #3 onto the navigation controller?
Or do I need to push all three views onto the navigation controller
in View #1?
Or...?
Thanks in advance,
Jim
The UIViewController has been designed to work hand in hand with UINavigationController. When pushing a new view, a UINavigationController will inject references to itself and to a UINavigationItem containing metadata about the navigation (back button with the title of the view behind it etc...).
Generally, you want to initialize your UINavigationController with Interface Builder using the "NIB Name" field to specify the "root view controller" (i.e. the first view to appear which should not have a back button). The equivalent in code roughly looks like this:
UIViewController *rootController = [[UIViewController alloc] initWithNibName:#"RootController"];
UINavigationController *navCtl = [[UINavigationController alloc] initWithRootController:rootcontroller];
Then, when you need to push a new view controller (probably in your didSelectRowAtIndexPath delegate method in your rootController)
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController"];
[self.navigationController pushViewController:secondViewController];
[secondViewController release];
Notice that you didn't have to create the self.navigationController property, it is already defined in UIViewController and will be injected with the right reference depending on the current state of the navigation. It works like magic!
The DrillDownSave sample code from the Apple Developer site:
https://developer.apple.com/library/ios/#samplecode/DrillDownSave/
does exactly what I am looking for with three hierarchy levels of
views using the navigation controller. Thanks for your answers.
Jim
In general all of your hierarchy should be contained in a single UINavigationController. I am not sure if nesting them is even supported.
How would you do this IF the subsequent views are additional instances of the same controller, that is a true hierarchy of nothing more than table views... the example shows hard coded views... but they essentially do the same thing. My OO background says if I alloc/init a new instance of a controller, shouldn't I be able to push that, then have its state restored on pop (back button)? That doesn't seem to work for me. Each instance of the controller (UITableViewController) has its own instance of an array as its data...