I created an app using the Tabbed Application template (without using a storyboard) and added several tabs along with their functionality. Now I want to add another tab that will have Master Detail functionality. There doesn't seem to be a way to use the Master Detail template without creating a new app. I tried creating a new app with the Master Detail template just so I could look at the code it generates but I can't figure out how to incorporate that code into my existing tabbed app. How should I proceed?
You can do it like this... (Adding example to Phillip's answer)
MasterViewController *masterViewController=[[MasterViewController alloc] init];
UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:masterViewController];
[masterViewController release]; //if not ARC
tabbarController.viewControllers=[NSArray arrayWithObjects:navigationController,
viewController1,
viewController2,
//More view controller objects,
nil];
[navigationController release]; //if not ARC
MasterViewController may contain a UITableView as subview or it may simply be a UITableViewCotroller (as you need Master-Detail flow.).
On an iPhone, a master/detail structure is basically a table view controller embedded in navigation controller and another custom view controller that is pushed when selecting a cell in the table.
If you're doing this in code, init your table view controller, init the navigation controller with the table view controller as its root, and update the tab bar controller's viewControllers property.
to get your whished behaviour in storyboards drag a navigation control in and make THAT a 'child' of the tabbar
Related
I got a tabbed application like this:
and already set up everything like it should look, but it won't function yet. I already googled my problem and they said you first need to set up a NavigationController with the table view as rootView and then the NavigationBar but I really couldn't figure it out. Hope someone of you can help me.
Based on your response to my comment on your question here is what you should be doing:
First off, in order to make it look like the settings app table, you will need to change the style of your UITableView to UITableViewStyleGrouped.
Your hierarchy will consist of the following:
The viewcontroller that is actually added into your UITabBarController viewControllers array(since I see you have a tabbar as your lowest level of navigation) should be an UINavigationController. The root viewcontroller of the navigation controller should be the uiviewcontroller subclass you made that contains your table view. (let's say it's called SettingsViewController)
SettingsViewController *settingsViewController = [[SettingsViewController alloc] init];
UINavigationController *settingsNavController = [[UINavigationController alloc] initWithRootViewController:settingsViewController];
You will probably need to create a different UIViewController subclass for each type of detail pane you're going to want (if they have different functionality).
In the didSelectRowAtIndexPath UITableViewDelegate function, you will create the appropriate detail viewcontroller and push it onto your navigation stack.
Let's say you have a volume settings view controller as an example. The following is the code you would have in the function I just mentioned. Keep in mind you also need to actually check the index and/or section of the selected row to figure out which detail view should be shown.
VolumeSettingsViewController *volumeSettings = [[VolumeSettingsViewController alloc] init];
[self.navigationController pushViewController:volumeSettings animated:YES];
By default, this will function pretty much like the Apple Settings app navigation. The navigation bar will automatically have a "back" button to take you back to the settings view.
If you are using a Storyboard, select your view controller, go to the "Edit" menu and choose, "Embed in Navigation Controller."
If not using story boards, assuming this will be done in code, you need to create things in a reverse order of their hierarchy - something like this:
Create an instance of the Einstellungen tab's TableViewController using initWithNibName:
Create a UINavigationController using initWithRootViewController: and setting the Einstellungen as the root
Create a UITabBarController and set your navigation controller as one of the view controllers of this tab bar controller
Add the tab bar controller as a subview to the main window in your application delegate
This will create this hierarchy:
Tab bar controller
->view controller: Navigation Controller -> root view controller: Einstellungen
I have created a tabbarcontroller (with its default two view controllers) using interface builder in XCode 4.2.
But, when I run the application, the tab bar seems to be locked and I can't choose the other tab. Why is that?
PS: I haven't changed any property of the tab bar or tabbarcontroller in XCode.
How did you go about creating the tab bar? Did you have an initial view and then go to the Edit menu -> Embed In -> Tabbar Controller or did you start with nothing and drag in tab bar controller?
Either way, I just created a project with a single view and tried both ways - but the tab still worked. (if you do it by dragging the tab bar controller from the utility pane, you have to also select 'is initial view controller' if you replace the original view created with the project.
EDIT after your comments:
You don't really need to synthesize the tab bar controller in your AppDelegate - storyboarding will take care of this and you can reference it from code without needing generated synthesizers. Just design the layout in storyboard first by dragging in a tabbar controller (this will automatically create the two view controllers by default). Then select the tabbar controller and under the utilities panel, you'll see the 'is initial view controller' checkbox. Make sure it's checked. Then run your project.
Apologies - assumed because you were using XCode 4.2 that you were using storyboards. Perhaps you could try instantiating a tabbar controller fully in code instead of using IB at all. This is how I usually do it....
// Create the main tabbar controller
tabbarController = [[UITabBarController alloc] init];
// Create the first view controller
MyFirstViewController *v1 = [[MyFirstViewController alloc] initWithNibName:#"MyfirstViewController" bundle:nil];
[v1 setTitle:#"Tab1"];
// Create second view controller
MySecondViewController *v2 = [[MySecondViewController alloc] initWithNibName:#"MySecondViewController" bundle:nil];
[v2 setTitle:#"Tab2"];
// Make an array of controllers for the tabbar
NSArray *tabbarControllerArray = [NSArray arrayWithObjects:v1, v2, nil];
// Set the view controllers used by the tabbar controller
[tabbarController setViewControllers:tabbarControllerArray];
// Release views (retained elsewhere)
[v1 release];
[v2 release];
// Add the controller to the subview
[window addSubview:[tabbarController view]];
// Make key and visible
[self.window makeKeyAndVisible];
Give this way a shot and see how you get on.
I have a view based app that works well. (In other words, I'm not going to start over with a Navigation-Based App template.)
It's an immersive app of sorts and I'm trying to add a Table View that loads in a new view when a button is pressed.
The loading the nib part works, but I can't seem to be able to add a navigation controller to the new view. I want to see a navigation bar on top with a done button and an edit button. Also, I want to the Table View entries to be empty.
I added a new file like so:
File-> New File -> UINavigationController subclass. I checked the UITableViewController Subclass and With XIB for user interface.
All I see when the view is pulled up is a blank Table View. I am able to customize things in the view controller.
What can I do to make the table show a navigation bar and be editable? I need some direction here please.
EDIT: I'm working with the latest Public SDK. (XCode 3.2.2)
The navigation bar usually comes with a navigation controller, not with the table view controller.
You can add the navigation bar manually, but that will require altering the table view, to change it to just a regular view with a table view inside of it, and changing your table view controller to be a regular view controller that manually handles the table view stuff.
The simpler alternative is to wrap your table view controller inside of a navigation controller before you display it. Something like:
MyTableViewController *myViewController = [[MyTableViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myViewController];
[myViewController release];
//Now display navigationController instead of myViewController, using something like:
[self presentModalViewController:navigationController animated:YES];
I have a view which contains a UIButton. When this is clicked, it calls a method that loads another NIB. Now, normally, that nib would load a view onto the stack, and everything would be fine. But, I am trying to load a Navigation Controller (so that I can have table views that are multiple levels deep), and all I get it errors.
What is the proper method for loading a Navigation Controller and putting it on the top of the stack?
As the other poster said you should create your Nav controller in your AppDelegate. If you are adding a new UIView to the stack like presentModalViewController you want to create the UIView then add the Nav Controller to it. If you don't want nav controller on that screen but the next just use the navController.hidden property I think it is.
To add the nav controller to the view do this:
NoticesView *noticesScreen = [[[NoticesView alloc] init] autorelease];
noticesScreen.delegate = self;
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:notices_screen] autorelease];
[self presentModalViewController:navController animated:YES];
Hope that helps towards your question. Still trying to find out exactly what your doing
Create the navigation controller in the app delegate. Push your mapview onto the stack as the first view. Push your tableview onto the stack as the second. If you started with a view-based app template, you won't have a navigationcontroller instantiated at all. (Been there done that) the easiest way out of this is to use xCode to make a navigation based applcation and then copy the code out of that. If you do already have a navigation controller, then just push the view controllers as above.
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/