Wanting to use a segmented control to swap views

I'm using Xcode 9 with Swift 4 and I'm laying out my app in Main.storyboard.


One of my UIViewControllers has a view with a UISegmentedControl and a UIScrollView. As the segmented control is toggled I want to show different controls in the view.


What's the best practice for doing this? I'd really like to layout the views in Xcode and not programatically.


I tried dragging UIViews onto the storyboard but Xcode won't let me. I can drag UIViews into the UIScrollView but things get cluttered and adding constraints seems tricky.


Any tips would be great. Thanks!

You can create all the controls in Interface Builder, then make them hidden (in Attributes Inspector, View section)


Then, in the IBAction associated to the segmentedControl, hide or show the controls as you want:


You will have code like :

    @IBAction func changeSelection(sender: UISegmentedControl) {
        let selection = sender.selectedSegmentIndex
            switch selection {
            case 0:
                firstControl.hidden = false
                secondControl.hidden = true
                thirdControl.hidden = true
          // …
             case 1:
                firstControl.hidden = true
                secondControl.hidden = false
                thirdControl.hidden = true
          // …
               case 2:
                firstControl.hidden = true
                secondControl.hidden = true
                thirdControl.hidden = false
          // …
               default: break
     }
}

Understood. I have this setup now.


What I'm wanting to know is what's the best way to layout the UI. I'm trying to do this in Interface Builder but one of two things happens, as I mentioned above:


"I tried dragging UIViews onto the storyboard but Xcode won't let me. I can drag UIViews into the UIScrollView but things get cluttered and adding constraints seems tricky."


I know how to hide the views I'm looking for a good way to design those views. Do I use UIViewControllers instead of UIViews and reference those views since I can't just drag a view into the storyboard without being in something? Just trying to see some options.


Thanks!

You cannot drag a UIView directly in Storyboard, you need to put it inside a viewController .


You said :

I want to show different controls in the view.

Is it views or controls that you want to drag into ?


Your intent for the global view design is not easy to understand.

Does UIScrollView uses all the space ? Or will controls be outside of it (that would be logic).

If that's the case, how many controls do you have in mind ?

If there are a limited number, it is not a serious problem to see them all in IB, even if they overlap a bit ; if tehre tens of them, that is effectively a problem and it would be esaier to create them programmatically (which I understand you wanted to avoid).

Just wanting to know the most practical way of designing UIViews that will be swapped out by a UISegmentedController.


Can you design the views inside of UIViewControllers and use those views within the UIScrollView? If so, that may be the most practical route since UIViews can't be placed directly within the storyboard. I'm not at my office right now or I'd try.


There's enough controls that it would be extremely cluttered and difficult (for me at least) to put accurate constraints on all of them.


Thanks.

So, you could create viewControllers with their controls and load the views in the IBAction as needed.

Their class is FirstViewController and SecondViewController respectively


From the tabBar buttons you would call first or secondController:


class SwitchingViewController: UITabBarController {
     private var firstViewController: FirstViewController!
     private var secondViewController: SecondViewController!

     override func viewDidLoad() {
        super.viewDidLoad()
        firstViewController = storyboard?.instantiateViewControllerWithIdentifier("First") as! FirstViewController
        firstViewController.view.frame = view.frame
        switchViewController(from: nil, to: firstViewController)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        if firstViewController != nil && firstViewController!.view.superview == nil {
            firstViewController = nil
        }
        if secondViewController != nil && secondViewController!.view.superview == nil {
            secondViewController = nil
        }
    }


    @IBAction func changeSelection(sender: UISegmentedControl) {
        if secondViewController?.view.superview == nil {
            if secondViewController == nil {
                secondViewController = storyboard?.instantiateViewControllerWithIdentifier("Second")
                                            as! SecondViewController
            }
        } else if firstViewController?.view.superview == nil {
            if firstViewController == nil {
                firstViewController = storyboard?.instantiateViewControllerWithIdentifier("First")
                                            as! FirstViewController
            }

        let selection = sender.selectedSegmentIndex
            switch selection {
            case 0:  switchViewController(from: firstViewController, to: secondViewController)
             case 1: switchViewController(from: secondViewController, to: firstViewController) 
             default: break
     }
}


    private func switchViewController(from fromVC:UIViewController?, to toVC:UIViewController?) {
        if fromVC != nil {
            fromVC!.willMoveToParentViewController(nil)
            fromVC!.view.removeFromSuperview()
            fromVC!.removeFromParentViewController()
        }
        if toVC != nil {
            self.addChildViewController(toVC!)
            self.view.insertSubview(toVC!.view, atIndex: 0)
            toVC!.didMoveToParentViewController(self)
        }
    }
}


import UIKit
class FirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    @IBAction func firstButtonPressed(sender: UIButton) {     // A button in the view
        let alert = UIAlertController(title: "Firs Button",
                        message: "pressed on the first view",
                        preferredStyle: .Alert)
        let action = UIAlertAction(title: "Done", style: .Default, handler: nil)
        alert.addAction(action)
        presentViewController(alert, animated: true, completion: nil)
    }
}


import UIKit
class SecondViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    @IBAction func secondButtonPressed(sender: UIButton) {     // A different button in second view
        let alert = UIAlertController(title: "Second Button",
            message: "pressed on the second view",
            preferredStyle: .Alert)
        let action = UIAlertAction(title: "Done", style: .Default, handler: nil)
        alert.addAction(action)
        presentViewController(alert, animated: true, completion: nil)
    }
}
Wanting to use a segmented control to swap views
 
 
Q