1

I currently have a Viewcontroller with 2 Container Views. The first is used as the navigation, and scrolls horizontally to show other buttons(like a dock or sliding tabs in material design). The second is the content. How would I control the content being shown in the second Container view through the first? Here's a picture that better illustrates what I am talking about. enter image description here

*Note I am only trying to update the Purple section of the view. Everything above the navigation container(blue) is static.

I've looked into this tutorial and will update if I figure anything out.

ethanfox27
  • 890
  • 1
  • 9
  • 25

3 Answers3

2

I recommend using delegations.

After pressing said button in your "navigation bar", let it tell the controller to change the second container view's content.


UPDATE:

In your navigation add protocol:

protocol NavigationDelegation: class {
    func userDidPressSomeButton(sender: NavigationViewController)
}

class NavigationViewController: UIViewController {
    ...
    weak var navDelegate: NavigationDelegation?
    @IBAction func someButton(_ sender: Any) {
        // some additional stuff
        ...
        // send delegation
        navDelegate?.userDidPressSomeButton(sender: self)
    }
    ...
}

Inside your main controller, conform to protocol and implement the delegation:

class YourMainViewController: UIViewController, NavigationDelegation {
    ...
    var firstEmbeddedViewController: NavigationViewController?
    var secondEmbeddedViewController: SomeOtherViewController?

    // Accessing your embedded controllers    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let controller = segue.destination as? NavigationViewController {
            embeddedViewController = controller
            // Setting your main controller to delegate to
            embeddedViewController!.navDelegate = self
        }
        else if let controller = segue.destination as? SomeOtherViewController {
            secondEmbeddedViewController = controller
        }
    }

    // Implement the required protocol function
    func userDidPressSomeButton(sender: NavigationViewController) {
        // You can now talk to your second embedded view, e.g.,
        secondEmbeddedViewController.someVariable = someValue
        secondEmbeddedViewController.someFunction()

        // You can also use the sender variable to access your navigation properties, e.g.,
        // let someText = sender.buttonOutlet.textLabel?.text
    }
    ...
}
Ray Tso
  • 566
  • 9
  • 17
  • Do you have an example I can reference? – ethanfox27 Mar 11 '17 at 18:35
  • I have updated my answer, here is also a youtube video link to give you a simplistic idea on how delegation works: [link](https://www.youtube.com/watch?v=D-xXRSCLNFQ) (delegation starts around 6:40) – Ray Tso Mar 11 '17 at 20:17
  • By main controller do you mean the purple container view or the VC with both container views? – ethanfox27 Mar 11 '17 at 21:54
  • The vc holding both container views. I named the purple container view's embedded controller as "SomeOtherViewController". – Ray Tso Mar 12 '17 at 03:11
0

Absolutely agree with Ray. Delegation is the best and the most flexible solution. I had almost the same issue but with master and detailed view. My solution is here How to update DetailView

Community
  • 1
  • 1
0

Main VC:

var container: ContainerViewController!

override func viewDidLoad() {
container!.segueIdentifierReceivedFromParent("first")

}


@IBAction func firstBtnPressed(_ sender: Any) {
let vc = "first"
 container!.segueIdentifierReceivedFromParent(vc)

}

@IBAction func secondBtnPressed(_ sender: Any) {
container!.segueIdentifierReceivedFromParent("second")
}


@IBAction func thirdBtnPressed(_ sender: Any) {
container!.segueIdentifierReceivedFromParent("third")
}





override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "container"{

    container = segue.destination as! ContainerViewController


}
}

Conatiner View

open class ContainerViewController: UIViewController {
//Manipulating container views
fileprivate weak var viewController : UIViewController!
//Keeping track of containerViews
fileprivate var containerViewObjects =         Dictionary<String,UIViewController>()

/** Specifies which ever container view is on the front */
open var currentViewController : UIViewController{
get {
    return self.viewController

   }
 }


fileprivate var segueIdentifier : String!

 /*Identifier For First Container SubView*/
@IBInspectable internal var firstLinkedSubView : String!


override open func viewDidLoad() {
super.viewDidLoad()



}
open override func viewDidAppear(_ animated: Bool) {
if let identifier = firstLinkedSubView{
    segueIdentifierReceivedFromParent(identifier)
}
}
override open func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func segueIdentifierReceivedFromParent(_ identifier: String){



self.segueIdentifier = identifier
self.performSegue(withIdentifier: self.segueIdentifier, sender: nil)


}




override open func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == segueIdentifier{


    //Remove Container View
    if viewController != nil{


        viewController.view.removeFromSuperview()
        viewController = nil



    }
        //Add to dictionary if isn't already there
        if ((self.containerViewObjects[self.segueIdentifier] == nil)){
            viewController = segue.destination
            self.containerViewObjects[self.segueIdentifier] = viewController

    }else{
        for (key, value) in self.containerViewObjects{

            if key == self.segueIdentifier{

                viewController = value


            }

        }


    }

    self.addChildViewController(viewController)
    viewController.view.frame = CGRect(x: 0,y: 0, width: self.view.frame.width,height: self.view.frame.height)
    self.view.addSubview(viewController.view)
    viewController.didMove(toParentViewController: self)


}

}

ethanfox27
  • 890
  • 1
  • 9
  • 25