08 Jan 2009, 02:20
Eastridge_pragsmall

James Kerr (40 posts)

I have an app that drills down through two tableViews to a detail view, all controlled by a navigationController.

I want the detail view to have three views that the user switches with a TabBar. I’ve seen this done in other apps, but can’t figure out how to make it work.

I added a TabBarController to the detailView’s nib file and set up it’s viewControllers, but it does not appear when the detailView is pushed onto the NavController’s stack. That is because the detailView’s nib has a view that is being loaded instead of the view belonging to the selected item’s viewController of the TabBarController.

Any ideas?

Thanks,

Jay

08 Jan 2009, 12:17
Biopic_100x100_pragsmall

Bill Dudney (917 posts)

Hi Jay,

I think you can solve the problem by pushing the tab bar controller onto the nav controller instead of one of your view controllers that is in the tab bar controller.

Hope this helps!

08 Jan 2009, 18:45
Eastridge_pragsmall

James Kerr (40 posts)

Hi Bill –

That’s where I’m confused. I created a nib file with the TabBarController, and no view, but when I push it onto the stack I get an error:

-[UIViewController _loadViewFromNibNamed:bundle:] loaded the “TabBarVC” nib but the view outlet was not set

If I add a view to the nib and wire it up, that view loads, but no TabBarController.

Actually, Apple’s docs say:

It’s very common to combine tab bar and navigation controllers, as illustrated in Figure 4. 
To do this, you simply add navigation controllers to a tab bar controller 
(however, you should never add a tab bar controller to a navigation controller).

But I have seen this application architecture in several apps (iProcrastinate is one example app), so I know it can be done.

09 Jan 2009, 14:15
Biopic_100x100_pragsmall

Bill Dudney (917 posts)

Hi Jay,

Well I guess I should try stuff out before recommending it :)

The error message is probably because the TabBarController does not offer the selected view controller’s view as its view while its loading out of the nib.

You could probably make this work but if the docs say its a no-no there are probably hidden complexities that will make it hack and slash until you get it just right. Then they will change the api :)

Is there another way to do your UI?

09 Jan 2009, 21:18
Eastridge_pragsmall

James Kerr (40 posts)

I worked out a solution:

Instead of trying to use a Tab Bar Controller, I added a UITabBar to the detail view and use it’s buttons to simply add subViews to the single detailView. That way my Navigation Controller is unaffected as the user switches between the various subViews with the tab bar, and can navigate back up the Navigation Controller’s hierarchy from any of the subViews.

Jay

13 Jan 2009, 17:36
Generic-user-small

Mark Spritzler (5 posts)

Jay, is there a way you can post some sample code for this. I am in the same situation. My Tab Bar Controller actually shows up, but the views for each tab does not. and the buttons on the tab doesn’t either, so I think your route is the correct route and would love to see a sample.

Thanks

Mark

13 Jan 2009, 19:18
Eastridge_pragsmall

James Kerr (40 posts)

Hi Mark –

I’ll include the code from my base detail view controller class, and describe my solution:

The app is a Navigation Controller app. The user drills down through two table views to a detail view. The detail view has 3 subviews.

For the base view for the detail view, set up in IB, the only element is a Tab Bar. No Tab Bar Controller, no other content at all. The content of the three screens of details are added to this base view as subviews. Each of the subviews is managed by it’s own view controller.

The detail view’s view controller is a Tab Bar Delegate. That allows the view controller to respond to selections on the tab bar. The detail view controller instantiates the viewController represented by the leftmost Tab Bar item and loads it’s view as a subview when the detail view loads.

When the user selects another Tab Bar item, the detail view controller instantiates the appropriate view controller, and adds it’s view as a subview. Subsequent selections of tab bar items simply move the subview to the top of the stack. Code for the base detail view controller follows:

//
//  TrailViewController.m
//  ColumbiaTrailGuide
//
//  Created by James Kerr on 1/12/09.
//  Copyright 2009 __COlumbia Sportswear Co.__. All rights reserved.
//

#import "ColumbiaTrailGuideAppDelegate.h"
#import "TrailViewController.h"
#import "TrailDetailViewController.h"
#import "MapViewController.h"
#import "GearViewController.h"
#import "Trail.h"


@implementation TrailViewController

// Respond to user selections on the Tab Bar
- (void)tabBar:(UITabBar *)tb didSelectItem:(UITabBarItem *)item {
	NSLog(@"item tag: %d", item.tag);
	
	if (item.tag == 1) {
		
		if(mapViewController) {
			[self.view bringSubviewToFront:mapViewController.view];
		}
		else {
			[self loadMapView];	
		}
	}
	else if (item.tag == 2) {
		if(gearViewController) {
			[self.view bringSubviewToFront:gearViewController.view];
		}
		else {
			[self loadGearView];	
		}
	}
	else {
		[self.view bringSubviewToFront:detailViewController.view];
		[detailViewController setTrailDetails:appDelegate.currentTrail];
	}
	
}

// ----------------------------------------- SUB VIEW CREATION ----------------------------------------- //
// These functions instatiate the subView view controllers and add their views as subViews //

- (void)loadTrailDetailView {
	NSLog (@"Loading the Detail View");
	detailViewController = [[TrailDetailViewController alloc] initWithNibName:@"TrailDetailView" bundle:nil];
	
	
	[self.view addSubview:detailViewController.view];
	[detailViewController setTrailDetails:appDelegate.currentTrail];
}

- (void)loadMapView {
	NSLog (@"Loading the Map View");
	mapViewController = [[MapViewController alloc] initWithNibName:@"MapView" bundle:nil];
	
	[self.view addSubview:mapViewController.view];
	[mapViewController setDetails:appDelegate.currentTrail];
}

- (void)loadGearView {
	NSLog (@"Loading the Gear View");
	gearViewController = [[GearViewController alloc] initWithNibName:@"GearView" bundle:nil];
	[self.view addSubview:gearViewController.view];
}

// --------------------------------------- END SUB VIEW CREATION --------------------------------------- //


- (void)viewDidLoad {
	[super viewDidLoad];
	appDelegate = (ColumbiaTrailGuideAppDelegate *)[[UIApplication sharedApplication] delegate];
	tabBar.selectedItem = [tabBar.items objectAtIndex:0];
	
	
}

- (void)viewWillAppear:(BOOL)animated {
	[super viewWillAppear:animated];
	[self loadTrailDetailView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}


- (void)dealloc {
    [super dealloc];
}


@end

Hope this helps –

Jay

18 Jan 2009, 06:12
Generic-user-small

Mark Spritzler (5 posts)

Thanks Jay. I see that it took a bit of work. Nice job on finding a way to make it work. Just as something I saw in a tutorial video somewhere, was that they put a segmented control as the navigation bar’s Title when they go to that view. Then the segmented control would be the one to switch to the different detail view controllers. I think this approach would take about the same amount of work.

It is kind of a shame that a TabBarViewController can’t just be pushed onto the Nav stack and it all happen automagically. Oh well.

Mark

26 Mar 2010, 16:00
Ian_smaller_pragsmall

Ian Thain (37 posts)

Has anyone a working sample of this?

Thanks

Ian

  You must be logged in to comment