If you’ve never used the Unity3D ContentSizeFitter and HorizontalLayoutGroup components, they can be a little frustrating to get under control the first time. Even after using them a few times, I still occasionally forget a step or checkbox here and there. In this article I’ll show you how to use the Unity3D ContentSizeFitter and HorizontalLayoutGroup components to build a responsive scalable UI window. We’ll add the ability for it to expand and collapse at runtime. And the window will scale correctly across different resolutions with no extra work.
Building The Window
To start, you’ll need a Canvas. Your canvas needs a CanvasScaler component as well so it can automatically adjust the size based on your resolution.
The root of our window is created from a rect transform with a ContentSizeFitter added to it.
The HorizontalFit and VeritcalFit should be set to “Preferred Size”
Name the window “Collapsable Window”
The Collapsable Window will have a single child named “Window Contents”
This object has the following components.
- VerticalLayoutGroup – With ChildControlsSize checked and Child Force Expand Checked.
- ContentSizeFitter – With Vertical Fit set to “Preferred Size”
Adjust the width of the “Window Contents” to 500.
Make sure the Anchor is set to top left.
Window Content Sections
Under window Contents, we’ll create 3 children. These will represent different parts of the window. The first two are mandatory for the window to work right, while the third is an optional footer.
The first child is our Header. The header will have a bar to look like a typical window would, along with an expand/collapse button, and finally some header text.
Create the header by adding an Panel as a child of the “Window Contents”. Select an image you want to use for your background or keep the default and adjust the color.
Next, add a LayoutElement and set the minimum and preferred height both to 80.
Check the FlexibleHeight box and enter a value of 0. This will prevent the header from resizing to fill in extra space.
FlexibleHeight is typically set to a value of 0 or 1, with 0 meaning do not resize, and 1 meaning resize to fill extra space as needed
Buttons (Expand and Collapse)
Our header is going to have two buttons, one to expand, and another to collapse. The user will only ever see one of these buttons at a time, based on the state of the window.
Create a button and name it “Expand Button”.
Delete the text object child, and change the image to be a downward facing arrow (or whatever other icon you want for expanding).
Anchor the button to the left and set the Pox X to 20.
Duplicate the button and name the copy “Collapse Button”. Flip or replace the image.
You can flip the image by changing the Y scale to -1.
On the expand button, add an OnClick event, assign the “Expand Button” to it and select GameObject.SetActive with the checkbox Unchecked.
Add another event, but this time drag the “Collapse Button” to it and select GameObject.SetActive with the checkbox Checked.
Select the Collapse Button and create the same events, but reverse the check state.
We’ve made a toggle! Uncheck the Expand Button’s active box (top left of the Inspector), and press play. You should be able to toggle between the two buttons.
Header Text – (optional)
Before we finish the header, we’ll want to add some text..
Create a text object and anchor it to the right. Set the “Right” value to 20 so it has a little margin from the edge.
On the Text component, check the “Best Fit” box and set the color / font as you like them.
You could also use TextMeshPro for your text. If you haven’t tried it out yet, check out my post here.. it’s great..
Now that we have the header and our expand button, we need something for it to actually show.
Create another Panel child on the “Window Contents”. It should be a sibling of the Header.
Name it “Body”
Look at the Image component – This is going to be the background image for our window. The ImageType must be set to Sliced.
If your imageType is set wrong, you may see the window expand to a giant size, this happened because it’s attempting to match the sprites resolution.
Add a ContentSizeFitter, with HorizontalFit left at “Unconstrained” and VerticalFit set to “Preferred Size”
You’ll notice a warning on the ContentSizeFitter. This is expected and normal behavior so don’t worry about it.
Add a VerticalLayoutGroup. Set the Left, Right, Top, and Bottom to 10.
Check all 4 checkboxes for Width & Height.
Under the “Body” add a button, a slider, some text, and whatever else you’d like in the window.
What you add is totally up to you, but make sure you add something or your window body won’t have anything to show and won’t be visible.
For each child of the “Body”, add a LayoutElement and set the Min Height and Preferred Height to values that make sense for your component. In my test project, I set them all to values ranging from 40-60.
Leave the width boxes & flexible boxes unchecked.
It’s time to add the footer. This is optional but I like to have it on the default window and disable it when we don’t want to use it.
Create another Panel under the “Window Contents” object.
Add a LayoutElement and set the Min Height & Preferred Height values to 30.
Set FlexibleHeight to 0.
Select an image for your footer background and add some text if you like.
It’s time to jump back to the buttons. Right now, they toggle each other, but we want them to also toggle our “Body” & “Footer” objects.
Add two onClick events to the “Expand Button”. Drag the Body to one, and the Footer to the other.
Select GameObject.SetActive and check the box.
Collapse Button Events
Repeat this process for the “Collapse Button”, but this time with the box unchecked.
You can download the project example here as an asset pack. It includes a single scene with the window setup similar to what’s shown here (without any purchased assets included)