Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a container view size itself by the components inside it in storyboard

Tags:

ios

swift

I have added a container view to a UIViewController in my storyboard that is managed by a separate UIViewController. This container view needs to have a height associated with it in order to lay out the items correctly. However, the height of this container view is dynamic, because it contains a UITextView among other items. Before, when I didn't use a container view, auto layout calculated the height of the items for me. Now I've moved everything to a container view it seems like this isn't possible. Am I going to have to manually calculate the height of my container view and apply it to a constraint, or is there a way to let auto layout deal with it?

like image 596
Tometoyou Avatar asked Nov 26 '18 12:11

Tometoyou


People also ask

How do I add a container view to a storyboard?

Open Main. storyboard and select the view controller of the scene that is already present. Open the Identity Inspector on the right and set Class to MasterViewController in the Custom Class section. With the view controller selected, choose Embed In > Navigation Controller from the Editor menu.

What is a container view controller?

Container view controllers are a way to combine the content from multiple view controllers into a single user interface. Container view controllers are most often used to facilitate navigation and to create new user interface types based on existing content.


1 Answers

You can do this, but you need a little bit of code.

When a UIViewController is embedded in a container view, its "root view" has its .translatesAutoresizingMaskIntoConstraints set to true, and its frame is automatically set to the bounds of the container view.

If your embedded VC has constraints set to properly resize itself, you can disable .translatesAutoresizingMaskIntoConstraints on its root view when it is loaded.

As an example, suppose we have this layout, and the label in the "content VC" will have a variable number of lines:

enter image description here

We want the container view to automatically change its height so all the text will fit. But, if we add 10 lines of text, the "default" result will be:

enter image description here

So, we give the container view Top/Leading/Trailing constraints of 8 (so we have a little padding on the sides), and a Height constraint of 128... but we change the Priority of the Height constraint to 250 (Low). This satisfies IB, but gives us flexibility for its height at run-time.

In our "content VC" we add a label and constrain it Top/Leading/Trailing/Bottom all to 8 (again, just for some padding) and, of course, Number of Lines set to 0.

Now, in our main VC, we implement prepare(for segue...) and disable .translatesAutoresizingMaskIntoConstraints on the embedded VC's root view:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    if let childViewController = segue.destination as? MyContentViewController {
        childViewController.view.translatesAutoresizingMaskIntoConstraints = false
    }
}

Now, at run-time, the intrinsic height of our label will increase the height of its superview (the root view), and that will override the container view's Low Priority Height constant, resulting in:

enter image description here

Here is the complete code for both VCs:

import UIKit

class MyContentViewController: UIViewController {

    @IBOutlet var theLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        // add 10 lines of text to the label
        theLabel.text = (1...10).map({ "Line \($0)" }).joined(separator: "\n")

    }

}

class ContainerContentViewController: UIViewController {

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)

        if let childViewController = segue.destination as? MyContentViewController {
            childViewController.view.translatesAutoresizingMaskIntoConstraints = false
        }
    }

}
like image 167
DonMag Avatar answered Sep 19 '22 14:09

DonMag