I'm in the process of creating an application for the iPhone for a client of ours and I'm stuck. Basically the application has a homepage (so to speak) which is simply a grid of (custom) buttons that when pressed takes you through to a specific part of the application. The home page is fairly plain with no navigation or tab bars displaying. However the majority of the other areas require navigation that will start at the point the area is first entered for instance I click from the home page into an area and from there I could click further into the app and at any point I can use the navigation controller to get all the way back to the first page of that area.
I've written a couple of test apps that use navigation and seen many examples while trying to figure this out but they all have the Navigation Controller implemented in the App Delegate and then display it in the Main Window but I don't want it to be displayed in the first view.
Firstly, is what I'm trying to do possible? (I suspect it is because most things are). And secondly what is the preferred way of achieving it? Any help would be much appreciated.
you can use a Navigation Controller even for the root level, then show/hide the navigation bar as necessary when you push or pop items on the navigation stack.
You should look into the -setNavigationBarHidden:animated: method on UINavigationController, which you could call in -viewWillAppearAppear: and -viewWillDisappear or in the navigation controller's delegate.
If your "Home Page" is just a UIViewController, you can present a UINavigationController modally which will allow you to navigate through to different areas. From your "Home Page" I would call the following:
NextViewController *nextView= [[[NextViewController alloc] initWithNibName:nil bundle:nil] autorelease];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:modalViewController];
[self presentModalViewController:navigationController animated:YES];
Related
I would like to combine UITableView and UINaviationController in an app but as a newbie most apps I've seen just send you straight to the results view (UITableView). But, I guess a "normal" search application does not assume you have the results on the first screen. There should be a search form on first screen with input fields and a button that triggers the search process and show some results and navigation.
So, I'm just trying to replicate this normal behaviour in my app. I've already made the search form (no navigation shown on it, of course) and a seperated View called "ListingViewController" with its related View and containing a UITableView and where I think I should add the Navigation...The next idea will be to make a DetailViewController and possibly and ListingMapController to show the listing in a GoogleMap.
So, where I'm stuck at is how to add this Navigation Controller ?
Some suggested me to add it in the SearchViewController delegate...
But I don't want a navigation on search form of course...
Some suggested me to open the Navigation controller modally...
But, I"m also planning at adding a Tab Bar to allow user to see other informations (like About,etc...) and with a modal Nav controller I don't know if they will still see the bottom Tabbar...
Any suggestions? What do you think is of best practices especially to avoid my app of being rejected by Apple?
Thx in advance for reading and helping!
Stephane
You could init the navigationController with your View Controller as the root view Controller. Then hide the navigationBar (if you need to). You would then add the navigationController.view as the subview. This will basically look like the original view controller. Then you can pushViewController: animated: to push the results view Controller.
So, for example in your AppDelegate (or in the proper view controller):
Create a property and ivar for a UINavigationController and hook up its outlets in interface builder. Then set your search controller as the root view controller for the nav bar, and add it as a subview.
MySearchViewController* searchController = [[MySearchViewController alloc] init];
self.myNavigationController = [[UINavigationController alloc] initWithRootController:searchController];
[searchController release];
self.myNavigationController.navigationBarHidden = YES;
[self.window addSubview:self.myNavigationController.view];
[self.window makeKeyAndVisible];
Then of course in your searchController, you would simply say:
ResultsViewController* myResultsViewController = [[MyResultsViewController alloc] init];
//You may want to create another init method and pass in some arguments like an array:
// [[MyResultsViewController alloc] initWithResults:results];
then push the viewController
//This is in your search controller class
[self.navigationController pushViewController:myResultsViewController Animated:YES];
[myResultsViewController release];
from the results viewController, to get back you pop the view controller off of the navigationController view controller's stack.
//In results view controller perhaps in some IBAction for a back button:
-(IBAction)backButtonPressed:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
I'm new to iPhone development (except developing with cocos2d).
I want to create a simple application that have one window with a button. When i press the button i want some other window to be shown.
Where can i read how do such things?
Also i don't understand well what is View, ViewController, Window. I've read the your first iOS app example.
Look for tutorials on UINavigationController, like this one.
For the meaning of view and view controller you certainly want to read the apple references or in wikipedia. The topic there would be MVC Pattern.
As to your concrete problem:
There is usually only one window in iPhone apps so you certainly want to have a button on a view and if you push that button that view disappears and instead a new view is shown.
You accomplish that by removing the view with the button from its superview ( have a look at the topic tree hierarchy ) and then add the view you want to bee shown as a subview to the main window .
Bottom line is there is one main window and you put views onto it by it's addSubview method. And you remove views by calling their removeFromSuperview method
You should to read it again or google it until you'll understand it well.
view is the graphic output, while view controller is what "manage" the behavior of the view in every event.
your function to navigate -
(IBAction) ButtonClicked
{
static YourViewController *viewController=nil;
if(viewController==nil)
viewController=[[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];
[self.navigationController pushViewController:viewController animated:YES];
}
I've got a sample application on http://github.com/niklassaers/Test-iPhone-TabBar-App that shows my problem: I have a regular view-based application, and at some point (in this case when I click a button) I want to load a tabbar controller and display it. I believe this is what I should be doing:
MyTabBarController *tabs = [[MyTabBarController alloc] initWithNibName:#"TabBar" bundle:nil];
[self.view addSubview:tabs.view];
Unfortunately, this brings up a bit of black in the bottom of my main view and nothing more. I believed it should bring up the tabbar, the tabs, and the selected view. What is the correct way of loading a TabBarController (or making a TabBar controller if that's what I've done wrong) in a view-based application?
Cheers
Nik
You should use a UINavigationController, then just push the tabs controller onto the nav controller when you're ready to display it.
Here is my problem:
I've read a lot about how to use a tab bar within a navigation based application, but i still can't figure it out. I have tried both to use and avoid using a tab bar controller, but i just can't find the solution.
I already have a navigation based app working. I have several nib files (views), each one with its own view controller, that i programmatically push onto the navigation controller stack. I need one of this views to have a tab bar that allows me to switch between some of the others. I understand how the tab bar works, and i do think what i need is to use a tab bar controller, since it would allow me to define the view controllers associated with each tab bar item, and manage all about them. However, i can't see how to do it.
If i do declare a tab bar controller in my "tabBarViewController", draw the tab bar controller in my "tabBarView" and link them with the IB, it will give me an error (I reckon this is because i haven't really pushed the tab bar controller's view? do i need something equivalent to "[window addSubView:[tabbarcontroller view]]?). In this case, all i need to know is how to "see" the tab bar controller's top view controller's view within a view controller i have already pushed.
If i try not to use a tab bar controller, as i have read is the best solution to this problem, ¿how do i manage tab bar items, the switchs between them, etc?
I would really appreciate your help.
You can't push a tab bar controller onto a navigation controller stack. There's just no supported way to do it.
What you may want to consider instead is creating your own instance of UITabBar, then using a delegate that conforms to UITabBarDelegate. That way, your delegate will receive the tabBar:didSelectItem: message whenever a tab bar item is selected by the user. You'll have to manage the NSArray of items for the bar yourself, though, without using IB.
Once you've got that figured out, all that's left to do is push a regular UIViewController onto your navigation stack like any other, and just have that controller manage your tab bar and delegate.
I just made an App with a tabBar controller and 5 navControllers. All you need to do is load the nibs and navigation controller inside the first element of the tabBar controller. You can HIDE the tabBar even if the views are inside it, and make it appear in the view you need it to.
You can do this with a bit of code, like so:
FooViewController *foo = [[FooViewController alloc] init];
BarViewController *bar = [[BarViewController alloc] init];
UITabBarController *tabby = [[UITabBarController alloc] init];
[tabby setViewControllers:[NSArray arrayWithObjects:foo, bar, nil] animated:NO];
[self.navigationController pushViewController:tabby animated:YES];
[foo release];
[bar release];
[tabby release];
You could probably do it with IB as well, just load the tab bar controller from a nib.
I built a sample project that demonstrates this in action, you can download it from http://s3.thismoment.com/navtab.zip
I'm trying to implement a UI structured like in the Tweetie app, which behaves as so: the top-level view controller seems to be a navigation controller, whose root view is an "Accounts" table view. If you click on any account, it goes to the second level, which has a tab bar across the bottom. Each tab item shows a different list and lets you drill down further (the subsequent levels don't show the tab bar).
So, this seems like the implementation hierarchy is:
UINavigationController
Accounts: UITableViewController
UITabBarController
Tweets: UITableViewController
Detail view of a tweet/user/etc
Replies: UITableViewController
...
This seems to work[^1], but appears to be unsupported according to the SDK documentation for -pushViewController:animated: (emphasis added):
viewController: The view controller that is pushed onto the stack. It cannot be an instance of tab bar controller.
I would like to avoid private APIs and the like, but I'm not sure why this usage is explicitly prohibited even when it seems to work fine. Anyone know the reason?
I've thought about putting the tab bar controller as the main controller, with each of the tabs containing separate navigation controllers. The problem with this is that each nav controller needs to share a single root view controller (namely the "Accounts" table in Tweetie) -- this doesn't seem to work: pushing the table controller to a second nav controller seems to remove it from the first. Not to mention all the book-keeping when selecting a different account would probably be a pain.
How should I implement this the Right Way?
[^1]: The tab bar controller needs to be subclassed so that the tab bar controller's navigation item at that level stays in sync with the selected tab's navigation item, and the individual tab's table controller's need to push their respective detail views to self.tabBarController.navigationController instead of self.navigationController.
The two previous answers got it right - I don't use UITabBarController in Tweetie. It's pretty easy to write a custom XXTabBarController (plain subclass of UIViewController) that is happy to get pushed onto a nav controller stack, but still lives by the "view controller" philosophy. Each "tab" on the account-specific view (Tweets/Replies/Messages) is its own view controller, and as far as they are concerned they're getting swapped around on screen by a plain-ol UITabBarController.
I'm building an app that uses a similar navigation framework to Tweetie. I've written a post about how to do this on my blog www.wiredbob.com which also links to the source code. It's a full template you could take and use as a basis for another project. Good luck!
It's possible to add a UITabBar to any UIViewController. That way you don't actually have to push a UITabBarController and therefore stay within the guidelines of the Apple API.
In interface builder UITabBar is under "Windows, Views & Bars" in the Cocoa Touch Library.
I do this in a couple of my apps. The trick to adding a tab bar to a navigationController based app is to NOT use a TabBarController. Add a Tab Bar to the view, make the view controller for that view a TabBarDelegate, and respond to user selections on the tab bar in the code of the view controller.
I use Tab Bars to add additional views to the Tab Bar's view as sub-views, to reload a table view with different datasets, to reload a UIPickerView, etc.
I was struggling for the past hour to implement a UITabBar because it would get hidden when I tried to display my view; then I found this post:
Basically, make sure you insert your new view below the tabbar, per this line of code:
[self.view insertSubview:tab2ViewController.view belowSubview:myTabBar];
In my app, the root view controller is a UINavigation controller. At a certain point in the app, I need to display a UITabBar. I tried implementing a UITabBar on a UIView within the navigation hierarchy, as some of the previous posts suggested, and this does work. But I found that I wanted more of the default behavior that the tab controller provides and I found a way to use the UITabBarController with the UINavigation controller:
1) When I want to display the UITabBarController's view, I do this:
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = myUiTabBarControllerInstance;
2) When I want to return to where I was in the navigation hierarchy, I do this:
appDelegate.window.rootViewController = myNavControllerInstance;
This could be achieved by simply embedding the TabBarController in the Navigation Controller.
In the storyboard:
Drag a ViewController
Click on the ViewController's Scene
Click on editor >> Embed in >> Navigation Controller.
Drag a button on the same ViewController.
Drag a TabBarController
Connect the button on the ViewController to the TabBarController via push Segue Action.
In this case only the TabBarController's RootViewController would be in the Navigation Controller's stack. All The TabBarItems would have the Navigation Bar at the top and user can go to Home Screen at any time, irrespective of the selected TabBarItem
This could be done at any ViewController in the Navigation Controller's stack.
If it works, please suggest me how to increase the reputation so that I can post the images and the code in the next answer. :)
This is how i did it. This is actually pushing a tabbarcontroller onto navigation controller. It works fine. I didn't find anywhere in the documentation that apple doesn't support this way. Can someone give me link to this warning?
If this is truth, is it possible that apple refuses to publish my app to appstore?
-(void)setArrayAndPushNextController
{
MyFirstViewController *myFirstViewController = [[MyFirstViewController alloc] init];
MySecondViewController *mySecondViewController = [[MySecondViewController alloc] init];
myFirstViewController.array = self.array;
NSArray *array = [[NSArray alloc] initWithObjects:myFirstViewController, mySecondViewController, nil];
UITabBarController *tab = [[UITabBarController alloc] init];
tab.viewControllers = array;
[array release];
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:#"first title" image:nil tag:1];
UITabBarItem *item2 = [[UITabBarItem alloc] initWithTitle:#"second title" image:nil tag:2];
myFirstViewController.tabBarItem = item1;
mySecondViewController.tabBarItem = item2;
[self stopAnimatingSpinner];
[self.navigationController pushViewController:tab animated:YES];
[tab release];
[item1 release];
[item2 release];
}
I wrote a blog post on how I approached this problem. For me, using a modal view was a simpler solution than writing a custom tab-bar implementation.
http://www.alexmedearis.com/uitabbarcontroller-inside-a-uinavigationcontroller/