Search Unity

What's new with UIElements in 2019.1

April 23, 2019 in Technology | 9 min. read
Topics covered
Share

Is this article helpful for you?

Thank you for your feedback!

UIElements is a new retained mode UI framework for Unity, available now as a public API for Unity 2019.1. In its current form, it’s a tool that makes it easier for you to extend the Unity Editor. In-game support and visual authoring will come in future releases.

This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.

Traditionally, building custom Editor windows and inspectors in Unity meant using IMGUI, an immediate mode API. IMGUI makes it easy to start building user interfaces but fails to scale when you’re building more complex applications. It’s also difficult for the system to optimize rendering because the user can drastically change the structure of the UI at any time within the current frame. Lastly, all UI is declared in C# which means that any future tool for authoring UI visually would need to generate C# code, which is a complicated proposition.

In UIElements, as a retained mode API, the idea is that you build your UI hierarchy of objects and let the system render it for you. This way, the system can optimize what it draws, and when it draws, leading to better overall performance. This paradigm also lets you decouple your hierarchy and styling from functionality, which results in a better separation of concerns and more approachable UI authoring for both artists and programmers.

Retained Mode

The basic building block of UIElements is the VisualElement class. All elements are either a VisualElement or inherit from it. Individual VisualElements can be parented to each other to form your UI hierarchy. Layouting, styling, and other systems then traverse this hierarchy to properly render your UI to screen.

In the Editor, each EditorWindow has a rootVisualElement property which represents the top VisualElement of your hierarchy. Elements need to be added as children to this root in order for the system to know about them and draw them.

using UnityEditor;
using UnityEngine.UIElements;

public class ExampleWindow : EditorWindow
{
   public void OnEnable()
   {
       var root = this.rootVisualElement;
       SliderInt slider = new SliderInt();
       root.Add(slider); // Add slider as a child of root.
   }
}

As long as the element is in the hierarchy, it will continue to draw, update, and consume user events, without input from the developer. This is where retained mode differs from immediate mode the most. The developer only needs to declare what should happen, and when, but doesn’t need to manage the frame-to-frame rendering.

To stop drawing an element, like this slider, you can either make it temporarily invisible with a styling change or remove it permanently from the hierarchy.

// You want to easily hide/show dynamically...
slider.style.display = Display.None;

// or, you're done with this element. Make it go away.
slider.RemoveFromHierarchy();

Retained mode also allows for a document model that lets you separate your hierarchy (using UXML) and styling (USS) declarations into separate assets. In C#, you can focus on just binding your declared UI with functionality and data using the built-in query system and event system.

With separate assets for hierarchy and styling, authoring UI visually becomes a possibility. This will make it easier for all users to tweak, author, and design UI in Unity.

Reusable Templates (UXML)

You can assemble your hierarchy of elements entirely in C#. However, just like styles, most of your hierarchy won't change very much throughout the lifetime of your UI. Therefore, we recommend that you modularize your UI by defining your hierarchy in a separate XML-based asset called UXML.

<UXML xmlns="UnityEngine.UIElements">
   <VisualElement name="the-container">
       <Label class="blue-label" />
       <SliderInt low-value="0" high-value="100" />
   </VisualElement>
</UXML>

Tag names correspond to C# types, with full support for user-defined types inheriting from VisualElement. Attributes will be set on the new elements on creation, and nested tags will become children of their parent tag.

You can load this .uxml asset like any other Unity asset, constructing a VisualTreeAsset object in the process. You can then instantiate (or clone) this VisualTreeAsset under any element and as many times as you wish.

var uxml =
    AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/ExampleUI.uxml");
uxml.CloneTree(root); // Create the tags in uxml as children of root.

Getting to the elements that we just created via UXML is done via the query system described shortly below.

Shared Styles (USS)

Styles can be set directly on VisualElements via properties in C#. However, since most styles are statically defined, it makes sense to separate their descriptions from the UI logic in C#. UIElements uses Unity-specific StyleSheet assets, called USS, which uses a subset of the CSS standard. You can use the same selectors familiar from CSS to identify which elements should get which styles, while the styles themselves are key-value pairs.

/* By style class. */
.standard-label {
    padding: 6px;
}

/* By element name. */
#the-label {
    font-size: 60px;
}

/* By C# type. */
Label {
    color: rgb(68, 255, 93);
}

You can load this .uss asset like any other Unity asset, constructing a StyleSheet object in the process. You can then assign it to your desired element and it will automatically apply the styles within to this element, as well as all its children. If children are added afterward, the styles will be applied to them as well.

var uss = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/ExampleUI.uss");
root.styleSheets.Add(uss);

While styles can be applied by name attribute or by C# type, for better style reuse you can also assign your elements one (or more) style classes and match your styles in USS by these classes. You can think of them as tags.

<!-- Assign a style class in UXML: -->
<Label class="blue-label" />

// Assign a style class in C#:
var label = new Label();
label.AddToClassList("blue-label");

You can also add multiple StyleSheets to the same element and have multiple rules matching the same element. Use USS to setup complex overriding rules while reusing styles as much as possible. Iterating on shared styles, like the color of your generic button, becomes trivial - especially since you no longer have to wait for C# to recompile. StyleSheet (USS) asset changes are automatically applied in the Editor on file save.

UQuery

The query system in UIElements is called UQuery. It’s similar to its web counterpart jQuery in that it lets you find elements in your hierarchy using a combination of their name attribute, currently assigned style class list, and C# type.

// By style class and type.
var label = root.Q<Label>(className: "blue-label");

// By name (returns a VisualElement).
var container = root.Q("the-container");

You can also build a Query object for optimized reuse where you need to run a query many times on a dynamic hierarchy.

// Build the query once.
UQueryBuilder<SliderInt> query = root.Query<SliderInt>(classes: "blue-slider");

// Run many times to get updated results.
query.ForEach(slider => Debug.Log(slider.name));

Events

UIElements comes with an event system. Events are usually sent to specific elements and then propagate down and up the UI tree until they are consumed, but this propagation behavior is customizable. Basic events, like MouseMoveEvent, are sent by the system and you can register to receive. You can also define and send your own custom user events.

Events are the main way for you to know when a state in the UI has changed or the user has performed an action. In the example below, we detect when the user has changed the slider value and display this new value in the label element.

var label = new Label();
var slider = new SliderInt();
slider.RegisterCallback< ChangeEvent<int> >(evt =>
{
   label.text = evt.newValue.ToString();
});

Debugger

If your UI appears broken, or if you simply don't see elements that should be on screen, the UIElements Debugger will be your friend. It will feel familiar to those that have used the website debuggers in Chrome and Firefox.

To debug an element in your UI with this debugger, you can enable Pick and hover over it or you can right-click on it and select Inspect. The debugger displays the full live hierarchy of the current window on the left pane and a styles inspector on the right pane. In this styles inspector, you can look at what styles are assigned to an element and where each style value is coming from (ie. which StyleSheet asset and which selector). Finally, you can live append and edit style values and see their effects in your UI.

Other Features

  • Bindings: Many controls can be bound to SerializedObjects to link the UI with your asset data. Any element implementing the IBindable interface (like all our built-in fields) can accept a string binding path to a SerializedProperty. You can then explicitly Bind() your element hierarchy to SerializedObjects.
  • IMGUIContainer: If you have a lot of existing Editor UI written in IMGUI, you can use the special IMGUIContainer element to embed IMGUI UI within a UIElements UI as just another element. The IMGUIContainer takes a callback that serves as your OnGUI() loop, receiving all the events from outside as it normally would.
  • Scheduler: UIElements comes with a simple built-in scheduler. You can use the scheduler to delay a callback a set amount of time, and/or executed it repeatedly at a set interval.

Future Releases

We're actively working on supporting use of UIElements for in-game UI. In addition, we plan to have a visual workflow around UIElements to enable people to design and build functional UI with little or no C# coding.

In the meantime, more and more of Unity itself will be built using UIElements, including Inspectors, new tools using dedicated Editor windows, and toolbars.

We will continue to maintain, and in some cases improve, IMGUI and uGUI and we have no plans for obsolescence in the foreseeable future. That said, UIElements will become the recommended and most supported way to build UI in Unity, starting with the Unity Editor in Unity 2019.1.

How do I get started?

The Unite LA 2018 talk on UIElements is a good place to start. It comes with a sample project that you can use to follow along, highlights the main differences and equivalences between IMGUI and UIElements, and covers most of UIElements' main features in a functional example-driven way.

This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.

You can download the example project from GitHub.

For more in-depth information on the API, see Unity 2019.1 Manual.

April 23, 2019 in Technology | 9 min. read

Is this article helpful for you?

Thank you for your feedback!

Topics covered