UIElements Tutorial for Unity: Getting Started

In this Unity tutorial, you’ll learn how to use Unity’s UIElements to create complex, flexible editor windows and tools to add to your development pipeline. By Ajay Venkat.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Creating Preset Window Layouts

Now that you’ve covered some of the theory, you can move on to creating the base layout for your Preset Window.

Preset Window's base layout

This is a plan for the different sections within the editor window. You can represent sections, or panels, within UXML as empty VisualElements.

The different sections within the editor window each have their own functions:

  • Button Bar: Contains action buttons such as creating and deleting presets.
  • Preset List: A List view that you’ll populate with the presets you created.
  • Description: A simple description of the purpose of the editor window.
  • Preset Settings: All the settings of the preset that you can change and save.

You can break down the expected layout into a Visual Tree that you can easily replicate in UXML.

UXML Visual Tree

Creating Layouts in UXML

Open PresetWindow.uxml and delete the following label VisualElement:

<engine:Label text="I changed the text!" />

Now, you have an empty section where you can insert new VisualElements:

Where to insert the new VisualElements

Save the PresetWindow.uxml and reload the editor window in Unity. You’ll see a clean, empty window:

Empty Preset Window

Insert the following code into the empty section in the PresetWindow.uxml:

<engine:VisualElement name="ButtonHolder">
	<!-- 1 -->
</engine:VisualElement>

<engine:VisualElement name="Container">

	<engine:VisualElement name="LeftPanel">
		<!-- 2 -->
	</engine:VisualElement>

	<engine:VisualElement name="RightPanel">

		<engine:VisualElement name="RightTopPanel">
			<!-- 3 -->
		</engine:VisualElement>
	
		<engine:VisualElement name="RightBottomPanel">
			<!-- 4 -->
		</engine:VisualElement>

	</engine:VisualElement>

</engine:VisualElement>

All you’re doing here is replicating the Visual Tree diagram above in UXML. You can break down each section of the editor window into empty VisualElements that you can fill with content. Note that you’ve made some name changes:

  1. LeftPanel: Refers to the Preset List.
  2. RightTopPanel: Was previously the Description.
  3. RightBottomPanel: Formerly, the Preset Settings.

Now that you have a clean layout, it’s time to start making it look the way you want.

Making the Button Holder Layout

Your first step is to change the layout of the area that will eventually hold your tool’s buttons.

To start, open PresetWindow.uss and remove everything in it, then insert the following code:

#ButtonHolder 
{
	height: 50px;
	width: auto;
	background-color: rgb(21, 132, 67);

	display: flex;
	flex-direction: row;
}

The # symbol lets you use the name selector and style it as ButtonHolder. You’ve changed the background-color to a dark green, set the height to a fixed size and set the width to auto.

Notice how the # symbol selector is used to select VisualElements based on their name attribute.

When display is set to flex, all child elements will use the Flexbox layout system commonly used in HTML/CSS.

You’ve also set flex-direction to row. This means VisualElements that are children of #ButtonHolder will display left-to-right.

Save PresetWindow.uss and check the editor window. You’ll see the following:

Preset Window's new Button Holder

Next, you’ll make the layout of the Main Container look just right.

Setting up the Main Container’s Layout

To start changing the Main Container’s layout, insert the following code under the #ButtonHolder section:

#Container 
{
	background-color: rgba(242, 246, 250,1);
	display: flex;
	flex-direction: row;
	width: auto;
	text-color: rgb(51, 51, 51);
}

This will create a container with a flex-direction of row so that Unity can arrange the panels from right to left. But when you save and reload the editor window, you’ll notice there are no changes.

That’s because you want the height property of the #Container to change with the height of the editor window. To fix this, open PresetWindow.cs and add the following code below the OnEnable() function:

private void OnGUI()
{
    // Set the container height to the window
    rootVisualElement.Q<VisualElement>("Container").style.height = new 
        StyleLength(position.height);
        
}

Unity runs OnGUI() every frame the editor window is open, so you can use this area to perform dynamic changes to UIElements.

Every frame, the PresetWindow.cs queries the rootVisualElement to find an object of type VisualElement with a name of Container.

Once the query has found the VisualElement, it changes the element’s height to the position.height, which is the height of the editor window. You use the StyleLength class when a VisualElement’s style requires a length value.

Sometimes, visuals are easier to digest when trying to understand new layout topics, so here’s a further breakdown:

Visual breakdown of the code to set the container height

Querying is very important with UIElements, as it’s the primary way to get the references of VisualElements you create in UXML documents.

Save PresetWindow.cs and open the editor window:

Empty editor window with a new layout

Notice the white tint, indicating that the Container fills the editor window as you intended.

Filling the Main Container

Now that you have an empty Main Container with the layout you want, it’s time to give it some subcontainers.

Navigate to the PresetWindow.uss and insert the following code after the #Container section:

#RightPanel 
{
	position: relative;
	flex: 1;
	width: auto;
	border-width: 2px;
	border-color: rgba(21, 132, 67,1);
}

#LeftPanel 
{
	display: flex;
	-unity-text-align: middle-center;
	flex: 1;
	width: auto;
	border-width: 2px;
	border-color: rgba(21, 132, 67,1);
}

#RightTopPanel 
{
	border-width: 1px;
	border-color: rgba(21, 132, 67,1);
	-unity-text-align: middle-center;
	display: flex;
	flex: 1;
}

#RightBottomPanel 
{
	border-width: 1px;
	border-color: rgba(21, 132, 67,1);
	-unity-text-align: middle-center;
	display: flex;
	flex: 1;
}

This creates the layouts for the other subcontainers using flex: 1 to scale the elements evenly between two elements that share the same parent. To further understand flex layouts, check the Yoga Documentation.

Save the file and open the editor window to see a beautiful Ray Wenderlich-themed window:

The PresetTemplate.uss that you attached earlier will set the USS for the other VisualElements.

Adding the Core UIElements

Now that you have a base layout, it’s just a matter of adding the VisualElements that you need in the correct places.

Open the PresetWindow.uxml and look at the different sections where you can place VisualElements, marked by comment placeholders that were copied in earlier.

Code showing where to place VisualElements

At 1, insert the following code:

<engine:Button name="NewButton" class="ButtonList" text="New Preset"/>
<engine:Button name="ClearButton" class="ButtonList" text="Clear Preset"/>
<engine:Button name="DeleteButton" class="ButtonList" text="Delete Preset"/>
<editor:ObjectField name="ObjectField"/>

This creates three named buttons and an ObjectField. You’ll add actions and triggers to these VisualElements in PresetWindow.cs.

At 2, insert the following code:

<engine:Label text="Saved Presets" style="-unity-font-style: bold; margin-top: 20px;"/>

<engine:ListView name="ListView"/>

This creates a label for the title and a List view, which you will populate in PresetWindow.cs.

At 3, insert:

<engine:Label text="Description" style="-unity-font-style: bold; margin-top: 20px;"/>

<engine:Label text="This is a preset manager that will be able to create and save variations of this GameObject so that various styles can be tested throughout the development of the game." style="margin-top: 20px; white-space: normal; line-height: 5px; font-size: 15;"/>

These two labels describe the editor window, which is a good example of inline styling with UXML.

At 4, insert:

<engine:Label text="Preset Bound Values" style="-unity-font-style: bold; margin-top: 20px; margin-bottom: 15px;"/>

<engine:TextField name="ObjectName" label="Object Name"/>
<editor:ColorField name="ColorField" label="Object Color"/>
<editor:Vector3Field name="SizeField" label="Object Size"/>
<editor:Vector3Field name="RotationField" label="Object Rotation"/>
<editor:FloatField name="AnimationSpeedField" label="Animation Speed"/>
<engine:Toggle name="IsAnimatingField" label="Is Animating"/>

This is a set of VisualElements created to modify the preset. You can use the label attribute to create a pre-made label next to the VisualElement to provide a description.

Open the editor window and be proud of the masterpiece you’ve created!

Editor window, with content

You’ll notice that there are hovering animations and rounded corners on the buttons at the top of the window. If you want to see what’s happening, open PresetTemplate.uss and explore its contents.

The ObjectField also mentions it has no type, meaning you have to configure it in PresetWindow.cs.