views:

974

answers:

1

I need to pop up a quick dialog for the user to select one option in a UITableView from a list of roughly 2-5 items. Dialog will be modal and only take up about 1/2 of screen. I go back and forth between how to handle this. Should I subclass UIView and make it a UITableViewDelegate & DataSource?

I'd also prefer to lay out this view in IB. So to display I'd do something like this from my view controller (assume I have a property in my view controller for DialogView *myDialog;)

NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"DialogView" owner:myDialog options:nil];
myDialog = [nibViews objectAtIndex:0];
[self.view addSubview:myDialog];

problem is i'm trying to pass owner:myDialog which is nil as it hasn't been instantiated...i could pass owner:self but that would make my view controller the File's Owner and that's not how that dialog view is wired in IB.

So that leads me to think this dialog wants to be another full blown UIViewController... But, from all I've read you should only have ONE UIViewController per screen so this confuses me because I could benefit from viewDidLoad, etc. that come along with view controllers...

Can someone please straighten this out for me?

+1  A: 

There is no such thing as a view controller being on the screen; its view is on the screen. With that said, you can present as many views as you want on the screen at once.

I would create a new view and view controller. You would not make a UIView be a UITableViewDelegate, you make a UIViewController be a UITableViewDelegate. But instead of doing that manually, instead make your new view controller a subclass of UITableViewController, if you're using iPhone OS 3.x+. You can then present this view controller modally.

You probably want to give the user a chance to cancel out of the selection. A good way to do that is to wrap your new dialog view controller in a UINavigationController and then put a "Cancel" button in the nav bar. Then use the delegate pattern to inform the parent view controller that the user has made their choice so you can pop the stack.

Here's what the code will look like inside your parent view controller, when you want to present this option dialog:

- (void)showOptionView
{
    OptionViewController* optionViewController = [[OptionViewController alloc] initWithNibName:@"OptionView" bundle:nil];
    optionViewController.delegate = self;
    UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:optionViewController];
    [self.navigationController presentModalViewController:navController animated:YES];
    [navController release];
    [optionViewController release];
}

Your OptionViewController .h will look like this:

@protocol OptionViewControllerDelegate;

@interface OptionViewController : UITableViewController
{
    id<OptionViewControllerDelegate> delegate;
}

@property (nonatomic, assign) id<OptionViewControllerDelegate> delegate;

@end

@protocol OptionViewControllerDelegate <NSObject>
- (void)OptionViewController:(OptionViewController*)OptionViewController didFinishWithSelection:(NSString*)selection;
// or maybe
- (void)OptionViewController:(OptionViewController*)OptionViewController didFinishWithSelection:(NSUInteger)selection;
// etc.
@end

Your OptionViewController.m will have something like this:

- (void)madeSelection:(NSUInteger)selection
{
    [delegate OptionViewController:self didFinishWithSelection:selection];
}

Which has a matching method back in your original view controller like:

- (void)OptionViewController:(OptionViewController*)OptionViewController didFinishWithSelection:(NSUInteger)selection
{
    // Do something with selection here

    [self.navigationController dismissModalViewControllerAnimated:YES];
}

There are plenty of examples throughout Apple's sample source code that follow this general pattern.

Shaggy Frog
Very helpful...especially the Protocol stuff! Thanks! but I don't think this addresses my need for this dialog to be more like an AlertView than a full screen view with a UINavigationController. Ideally it's a little bigger than a UIAlertView and has a small (3 rows) UITableView in it with a Cancel button below. Again, back to the UIViewController vs UIView in this case... there will be a view controller controlling the view still visible behind this modal "dialog". That said, is it still OK to have another view controller controlling the dialog? Sorry for confusion...
Meltemi
What is the reason you don't want to use a "full screen view"? Look through the apps on your device -- especially the ones from Apple -- and count the number of times that you see a list of 2-5 options presented in any other way. This is exactly how most apps do it; if not to be consistent, but also because it's what the user might expect. Note that using a UIAlertView isn't really appropriate since those are generally reserved for actions that the user must take immediately. Selecting an option from a list should be done using the best tool available for that task: a table view.
Shaggy Frog
You also have the option of using a UIPickerView in a UIActionSheet, this removes the need for a UITableView/controller and also gives you handy done and cancel buttons. If you want sample code I can post something as a possible answer.
Eric Schweichler
Well, Game Kit's peerPickerController is one example of a partial screen modal view with an embedded tableview... I understand that in MOST cases the way you suggest, Frog, is preferred and even makes most sense...but in this particular case of mine it doesn't... so question remains...how to? I've tried the UIViewController approach and that clearly fails as the SDK automatically fills to the bounds of the screen if UIViewController's view isn't full screen. So, I guess I'm left with a custom UIView. UIPickerView is good idea but I'm afraid my "cells" text will be too wide...
Meltemi