views:

62

answers:

3

I'm working on an app that has three table view controllers in a navigation stack. The root view controller and the second VC have toolbars, but I want to add a subview to the second view controller like this. (The color is just there for visualization.)

I want to add the view programmatically, since I haven't been able to do it with IB without major headaches. Right now, I've been able to kind of get what I want by drawing a UIView in the second view controller like this:

- (void)viewDidLoad {
      [super viewDidLoad]

      UIView *detailView = [[UIView alloc] initWithFrame:CGRectMake(0, 392, 320, 44)];
      detailView = [UIColor redColor];
      [self.navigationController.view addSubview:detailView];
      [detailView release];
}

The problem with this approach is that once the UIView is loaded in the second view controller, it stays loaded and is drawn in the third and root view controllers. I've tried a variety of methods of removing the UIView, including setting the detailView to nil in viewDidUnload, calling removeFromSuperview in didSelectRowAtIndexPath (which removed the view from the whole stack).

I've also tried adding the subview to self.view, but that pushes it below the visible area of the table view, so I have to scroll up to see it, and it snaps back down when I let go.

Clearly, adding this subview to the navigation controller is not the best way to do what I want, but I'm at a loss as to where to go from here.

+1  A: 

Not sure which behavior you're looking for but try one of these:

  • Assign the detailView to the tableFooterView property of the tableview on the second VC.

  • Reduce the height of the table view and add the detailView to self.view.

aBitObvious
A footer view wouldn't work since the subview needs to always be visible, ie the table view should scroll "behind" it.
Paul Ward
You should reduce the height of the table view or if you really want it to scroll behind it, add the detailView to self.view then do `[self.view bringSubviewToFront:detailView]` (before you release it).
aBitObvious
If I add the subview to self, then I'm attaching it to the tableview, so it scrolls with the tableview. I want the subview to be stationary, right above the toolbar.
Paul Ward
Ok, the VC is UITableViewController, not a UIViewController. It might be easier to change it to a UIViewController so you can easily manage the detailView separate from the tableView.
aBitObvious
Seems that way. Back to the docs for me.
Paul Ward
I've had to do this several times. Change your vc to inherit from UIViewController instead of UITableViewController, add a property of type UITableView called tableView, then connect your existing table view to that property in Interface Builder. You may have to adjust some code because of name collisions, but it shouldn't be too hard.
Robot K
+2  A: 

I don't like the approach. You should put your table view inside another view, and put your detail view together in that view.

Despite of that, I think you can remove your view in viewWillDisappear method of your view controller. I also notice that you did not keep your detailView as a private variable, which you should do because you need to reference it when removing it later (I still wonder how you have done it.)

Note that viewDidUnload is called in case of view unloading (i.e. releasing from its controller), so it is not related to navigation.

tia
+1  A: 

As you've already discovered, you definitely should not be reaching up into the navigation controller's view.

You want your SecondViewController to be an UIViewController that implements the UITableViewDelegate and UITableViewDataSource and whose view lays out the UITableView and the UIView you wish to use for your stationary 'footer' in it's own main UIView.

It helps to keep in mind that UITableViewController is ultimately is just a convenience for creating a view controller whose view consists entirely of a UITableView.

Anyway, rather than attempt to put a pile of that code inline in this answer, you can browse it (or svn co) from this read-only svn repo.

EDITED (now that it's not midnight, putting some code/explanation directly in answer):

For the controller to be pushed onto the nav stack that needs the footer create a new UIViewController-based class (do NOT check the 'UITableViewController subclass' box in the template selection dialog).

Add instance variables for the UITableView and the UIView that is to be the extra bottom view.

@interface SecondViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
    UITableView* tableView;
    UIView* customFooterView;
}
@property (nonatomic,retain) IBOutlet UITableView* tableView;
@property (nonatomic,retain) IBOutlet UIView* customFooterView;
@end

In IB add a UITableView and UIView to the existing root view for the controller and lay them out as desired (probably worth altering the auto-resize parameters too if your app can be used in both landscape and portrait). Hook up the two views to the outlets defined for them in the "File's Owner" and also ensure you hook up the UITableView's delegate and dataSource properties to point at the "File's Owner."

Then just implement the UITableViewDelegate and UITableViewDataSource protocols as appropriate for your application.

If you want to lay out the entire 'footer' view in IB then go right ahead. Otherwise you can easily add items programmatically in viewDidLoad (and remember to tear it down in viewDidUnload).

imaginaryboy