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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
UIElements Tutorial for Unity: Getting Started
35 mins
- Getting Started
- Creating an Empty Editor Window
- Understanding Visual Elements
- Exploring UXML Documents
- Analyzing a VisualElement
- Exploring the USS Document
- Exploring the Main Editor Window Controller
- Setting up the Editor Window
- Creating VisualElements Without UXML
- Attaching UXML and USS to the Editor Window
- Modifying UXML and USS Attachments
- Creating Preset Window Layouts
- Creating Layouts in UXML
- Making the Button Holder Layout
- Setting up the Main Container’s Layout
- Filling the Main Container
- Adding the Core UIElements
- Adding Functionality to the Editor Window
- Setting up the ObjectField
- Setting up Buttons
- Populating the List View
- Binding Values in UIElements
- Testing and Debugging the Editor Window
- Where to Go From Here?
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.
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.
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:
Save the PresetWindow.uxml and reload the editor window in Unity. You’ll see a clean, empty 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:
- LeftPanel: Refers to the Preset List.
- RightTopPanel: Was previously the Description.
- 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:
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:
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:
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.
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!
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.