views:

92

answers:

2

I want to use a modal view (UIViewController) as a "normal" view, which can be pushed on the navigation controller stack. Normally, a modal view is presented like this:

LoginViewController *myView = [[MyViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:myView];
[self.navigationController presentModalViewController:navController animated:YES];
[myView release];
myView = nil;
[navController release];
navController = nil;

But I want to do something like this:

[[self navigationController] pushViewController:myView animated:YES];

The problem is that my modal view has a right and a left button. So I would have to check how the view is loaded and present the buttons in another way. The idea behind this is to have the back button. So I can use the same modal view a few times.

Edit:

@petert:

Now I followed your example. My issue is that I'm using a UINavigationBar for the modal view. To get this UINavigationBar I create a navigation controller. I'm using the navigation bar because I have my buttons in it. So checking if parentViewController is of type UINavigationController does not work for me. I'm always getting a modal view. Here is how I do it:

// load modal view
MyViewController *myView = [[MyViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:myView];
[[self navigationController] presentModalViewController:navController animated:YES];
[navController release];
navController = nil;
[myView release];
myView = nil;


// load as normal view
MyViewController *myView = [[MyViewController alloc] init];
[[self navigationController] pushViewController:myView animated:YES];
+1  A: 

Good tips in this StackOverflow answer.

I prefer to use UIViewController's property:

@property(nonatomic, readonly) UIViewController *parentViewController

in a view controller's subclass:

Look at the value of the controller's parentViewController property. If it's an instance of UINavigationController, then you're in the navigation stack. If you're being displayed modally, it'll be an instance of your last view controller.

So in -viewDidLoad for example:

- (void)viewDidLoad
{
   if ([self.parentViewController isKindOfClass:[UINavigationController class]])
     {
        // navigation controller
        self.title = @"...";
     }
   else
     {
        // modal
        self.title = @"Modal";

        // add cancel and done buttons now...
     }
}

Or, a pretty simple solution would be to customize your init method to your MyViewController class to encode your intent for the view controller.

Add the following to the MyViewController header:

@interface MyViewController : UIViewController
{
  BOOL modal;
}

- (id)initForModal:(BOOL)isModal;

@end

Now in the implementation file:

@interface MyViewController ()
@property (nonatomic) BOOL modal;
@end

@implementation MyViewController

@synthesize modal;

- (id)initForModal:(BOOL)isModal;
{
  if (self = [super initWithNibName:@"MyViewController" bundle:nil])
    {
      self.modal = isModal;
    }

  return self;
}

- (void)viewDidLoad
{
  [super viewDidLoad];

  if (self.modal)
    {
      // add cancel and done buttons …
    }
  else
    {
      // assuming we're presented from a navigation view …
    }
}

Now to use this modally:

// load modal view
MyViewController *myView = [[MyViewController alloc] initForModal:YES];

Or not modally:

// load as normal view
MyViewController *myView = [[MyViewController alloc] initForModal:NO];

I'm assuming you're creating the view controller(s) from NIBs, but as always see the View Controller Progamming Guide for iOS and especially the section titled "Defining a Custom View Controller Class".

petert
Thank you for your provided sample code. I think it would work well, but I'm using a `UINavigationController` to present my modal view. Why I'm doing it is explained in my edited question. Perhaps you could provide a solution.
testing
Your support is great! This solution is quite simple and works well. Now some question for my understanding: 1) Why are doing a new interface declaration in the implementation file? 2) The `if` in the `initForModal` calls the super constructor and if he is successful he returns the object (`ViewController`) and if not he returns nil. Is this correct? In the `if` statement only a option is set if the object is not nil. 3) I need the property here because the variable is used above method borders?
testing
Glad it's helpful - 1) it's to hide the modal property, since it's not for use outside this classes implementation; 2) Yes absolutely, it's a general obj-c style for init methods; 3) I used a property just to make things simpler, I think the answer to your question is yes? Remember to vote the answer up too, if it's helped, thanks.
petert
A: 

For clarification: myView isn't modal. You just present it as a modal one.

If you just push it into a UINavigationController hierarchy it will behave like a "normal" one.

You can't push the same view controller onto the navigation stack several times. Just once.

Also see this for how to customize the view:

SO modal question

Alin
OK, I present it as modal view. Do you have an example for a "real" modal view? I don't want to push it at the same time on to the stack. What do you mean with just once? I can put it as normal view on the stack, but later not as modal view?
testing