Diggory
Diggory

Reputation: 645

What is the correct way to have a view overlay all other viewControllers across an app?

I am relatively new to iOS development, and am planning an app. The app will have several different scenes / ViewControllers which will take up the whole the screen.

I intend to always have a small button in the top left of the screen which would take the user back to the home page, whichever vc is currently showing.

I could place a separate but identical button in every viewController's view, but that seems inelegant and fragile.

My instinct after reading the View Controllers Programming guide is to create a View Controller Container which will be the root vc - this vc will have two child vcs - one with the home button in and the other underneath that which all the other VC's go in (effectively becoming the new root vc.)

Does this seem like a sensible solution to more experienced iOS developers? Is there a simpler solution?

Any advice thankfully received.

Upvotes: 4

Views: 4009

Answers (2)

Andrey Gordeev
Andrey Gordeev

Reputation: 32509

With Swift, you can take a power of protocols and protocol extensions. I wrote an article about this approach. In short you'll need the following:

  1. Create a protocol describing an overlay view controller.
  2. Encapsulate the logic of presenting/dismissing the view controller into that protocol using protocol extension.
  3. Create a protocol for the overlay host.
  4. Encapsulate the logic of instantiating the overlay view controller from storyboard into that protocol using protocol extension.

And you're all set. The usage would look like:

class ViewController: UIViewController, OverlayHost {
    @IBAction func showOverlayButtonPressed() {
        showOverlay(type: YourOverlayViewController.self, 
            fromStoryboardWithName: "Main")
    }
}

Source code: https://github.com/agordeev/OverlayViewController

Upvotes: 0

Bill Patterson
Bill Patterson

Reputation: 2558

I think that's likely your best solution. In iOS, a ViewController takes up all it's available space for it's view. Without a "container" view that you manager yourself, any view controller you put up is going to take up the entire window, covering anything you've displayed.

However, there's an alternate approach that may be simpler, depending on your project.

You could create a UIView object (your button) in some central place (say, your App Delegate class). That view could have a button that you attach to a method:

@implementation AppDelegate

- (void) someSetupMethod {
    UIButton* b = [UIButton buttonWithType:UIButtonTypeCustom];
    // setup whatever properties

    // Now set button to call a method *on this AppDelegate object* ("self"):
    [b addTarget:self action:@selector(homeButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

    // Store the button definition somewhere permanant
    self.reusableHomeButton = b;
}

- (void) homeButtonTapped:(id)sender {
    // do something to pop view controllers back to what you want.
}

Then, in your view controllers, they could all show the home button when they appear:

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

    AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    [self.view addSubview:appDelegate.reusableHomeButton];
}

This takes advantage of an intentional side-effect of [view addSubview:...] which is that if the view is already in some parent, it removes it from that parent first, then adds to the new view.

It also takes advantage of the fact that a button can send it's message to any object. It doesn't have to be the ViewController hosing the button's parent view.

This causes your button to be "moved" from one displayed view controller's .view to a new one whenever a new controller is presented.

Since the button has a target of a the AppDelegate object (and will therefore send it's message to that object), it works "from anywhere" as long as the app delegate object exists to receive the message (which it does as long as your app is running).

Upvotes: 1

Related Questions