34 Comments

The Easy Way to Switch Container Views in iOS

In my first blog post in this series, I offered a basic way to add a container view to your iOS project. Container views allow you to create a reusable component that other view controllers in your project can share.

Today, I will cover a simple way to switch between two container views—a useful trick when you have to show a different UI at runtime based on the state of your application or you design your app to transition to another view based on user interaction. If you want to follow along, I put the entire project on GitHub.

In this example, I’ll use a segmented control to switch between two container views which I’ll call A and B. I chose a simple fade transition to go from one to another.

Switching Component Views

Build the Example

1. First, add a container view to your view controller. I applied a blue color to the child view controller so you could tell the difference between the two.

2. Next, position and constrain the container view however you want it to appear in your parent view controller.

3. Then drag a second container view right on top of container view A as shown here.

add_container_view_b

4. Constrain container view B to have equal width and height to container view A, and center container view B to the middle of container view A. This way, any layout changes that happen to our first container view will be applied to the second. They should both be the same size and have the same position.

Now you should have two container views with independent child view controllers.  You can customize your child view controllers however you want. I added a purple color to B so you could see the difference.

Indicate Which View to See First

As it stands right now, if you build and run, container view B will be shown on top of container view A. I want to change that so that B is hidden initially and you see A. To do that:

1. Select container view B.

2. Change the alpha property of the view in interface builder from 1 to 0.

This will show container view A at startup and hide B.

finished_adding_container_views

You may be wondering if you could solve this problem by dragging an embed segue to connect the container view with the second child view controller. That way, you would have one container view with two child view controllers. Unfortunately, a container view can have only one embed segue and therefore only one child view controller. Having two container views solves this problem.

To switch between the two views, we have to add some code. Adding an outlet to your view controller for container view A and B lets you change the alpha property on the view that we want to hide/show. On the segmented control used to switch views, I added an action outlet for the “value changed” action called showComponent.


import UIKit

class ViewControllerSwift: UIViewController {
    @IBOutlet weak var containerViewA: UIView!
    @IBOutlet weak var containerViewB: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func showComponent(sender: UISegmentedControl) {
        if sender.selectedSegmentIndex == 0 {
            UIView.animateWithDuration(0.5, animations: {
                self.containerViewA.alpha = 1
                self.containerViewB.alpha = 0
            })
        } else {
            UIView.animateWithDuration(0.5, animations: {
                self.containerViewA.alpha = 0
                self.containerViewB.alpha = 1
            })
        }
    }
}

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *containerViewA;
@property (weak, nonatomic) IBOutlet UIView *containerViewB;

@end

@implementation ViewController

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

- (IBAction)showComponent:(UISegmentedControl *)sender {
    if (sender.selectedSegmentIndex == 0) {
        [UIView animateWithDuration:(0.5) animations:^{
            self.containerViewA.alpha = 1;
            self.containerViewB.alpha = 0;
        }];
    } else {
        [UIView animateWithDuration:(0.5) animations:^{
            self.containerViewA.alpha = 0;
            self.containerViewB.alpha = 1;
        }];
    }
}

@end

When the selectedSegmentIndex is zero, we want to display container view A. Otherwise, we want to show B. I used a simple UIView animation to animate the alpha of the two component views. The animation is optional. You could set the alpha property directly.

The Downside

This solution is pretty simple, but it does come at a cost in terms of memory usage. Both of the child view controllers for A and B are in memory the whole time your parent view controller is alive–even if you decide to only show one of them at runtime. Also, all of the rotation and appearance messages (such as viewDidAppear) received by the parent view controller are automatically delegated to the child view controllers. Since both view controllers are in the view hierarchy, they both receive these events. This could cause performance problems if you have time-consuming code. However, in most situations, these downsides are not an issue. In my next blog post, I will show you a way to avoid some of these downsides. If you would like to try this code out yourself to see it in action, I have the entire project on GitHub.


Catch up on my other posts in this series:


For more on using Xcode, read my series on unwind segues: