Create a ScreenManager
Code and workflows for navigate between different views using UI Builder and UI Toolkit

What you'll develop on this page

Navigating between different views in our TitleScreenUI
Navigate between different views using UI Builder by creating Navigation Scene with a ScreenManager.

Background on the UI Approach

Components of our UI

Often in games there is a "title" screen with options or settings the user sets up before going into the game. In this section we will implement the ability to switch between different UI views like that in this page.
We will create a new Scene called "NavigationScene." We choose the name "NavigationScene" because the users of Moetsi XR experiences usually need UI to "navigate" to the environment they want to join.
NavigationScene will have a GameObject that contains a "UI Document" Component which has a "Source Asset" field. We will put in a ScreenManager ("TitleSceneManager") that will control the display of different views in the Scene. You should think of the TitleSceneManager as the "switchboard" that decides which views are shown.
We will have 4 "views" within our TitleScreenManager:
    1.
    Title Screen (the first view you see)
    2.
    Host Game Screen (to host a local game)
    3.
    Join Game Screen (to join a local game)
    4.
    Manual Connect Screen (to manually connect to a game)
Asteroid NavigationScene screen flow
"ScreenManager" is not an official Unity term. It is a term we use to indicate a design pattern whereby a "managing" View handles the switching between different views.

How we'll build our UI

You will notice a pattern for how we build UI. We start with an UXML. Usually we put a custom Visual Element (cVE) as the first child of the UXML.

The Visual Tree

The visual tree holds all the visual elements in a window. It is an object graph made of lightweight nodes referred to as visual elements.
These nodes are allocated on the C# heap, either manually or by loading UXML assets from a UXML template file.
Each node contains the layout information, its drawing and redrawing options, and how the node responds to events.

VisualElement

VisualElement is the common base class for all nodes in the visual tree. The VisualElement base class contains properties for styles, layout data, local transformations, event handlers, and so on.
VisualElement has several subclasses that define additional behaviour and functionality, including specialized controls. VisualElement may have child elements.
You are not required to derive from the VisualElement base class to work with elements. You can customize the look and behavior of a VisualElement through stylesheets and event callbacks.
Within that custom Visual Element (cVE) we put all the elements that come to mind when we think of UI: text, buttons, labels, input fields, images (these are all also "Visual Elements" in UI Toolkit terminology) and give each of the elements a "Name" so that we can reference them within our custom Visual Element (cVE).
Standard Visual Elements are Visual Elements provided by Unity with standard functionality (label, textfield, buttons, input fields, images). cVEs will be created by us and they do things like add callbacks to children Visual Elements or set data to Visual Elements.
We will follow the flow of UXML > cVE > Standard Visual elements throughout this gitbook.
Our TitleScreenManager uxml/VE approach
    Admittedly, this might be a bit confusing without any context so let's just get to it!

Setting up our Components

    First let's begin by adding the necessary packages to our manifest
    Open the manifest.json file in your Project folder and add these three lines to the bottom:
1
"com.unity.ui": "1.0.0-preview.14",
2
"com.unity.ui.builder": "1.0.0-preview.13",
3
"com.unity.vectorgraphics": "2.0.0-preview.13",
Copied!
then find textmeshpro in the file (should currently be version 3.0.1) and update that line to the version of TextMesh Pro below, then save the manifest.json file:
1
"com.unity.textmeshpro": "3.0.3",
Copied!
Adding UI packages to manifest.json (updating TextMeshPro not seen in this gif but do it)
You might get warnings and errors after adding these packages.
This is because the packages are still a bit wonky. Fear not, these warnings and errors will not cause any problems; please ignore them. Each time you open the project the errors will appear, but they won't cause any trouble.
This does NOT mean from now on you can ignore all errors in the gitbook. Make sure you do not have any errors before you add these packages and note the type of errors that appear after you install the packages. These are UI Toolkit/UI Builder errors.
    Create a new folder in "Assets" called "UI"
    Within our "Scenes" folder, right-click, select "Create", then select Scene and name the newly created scene "NavigationScene"
    Double click on "NavigationScene" to open it
Creating UI folder and NavigationScene
    Right click in the Hierarchy and create an empty GameObject called TitleScreenUI
    Add an "Event System" (UI Toolkit) component

Class EventSystem

Use this class to handle input, and send events to a UI Toolkit runtime panel.
    Also add a "UI Document" component

Class UIDocument

Defines a Component that connects VisualElements to GameObjects. This makes it possible to render UI defined in UXML documents in the Game view.
    Notice the field in the UI Document component called "Source Asset"
      As mentioned in the Overview page of this section of the gitbook, this is going to be our "parent" for all our visual elements/uxmls
    Save the scene (the next thing we create will crash it)
Creating our TitleScreenUI GameObject
    Open the UI folder, right-click inside, hover over "Create", navigate down to UI Toolkit, and select "Panel Setting Asset"
      This will crash Unity (or at least it did in our testing)
      If that happens, just open Unity back up!
Creating a Panel Settings Asset (and crashing Unity)

Class PanelSettings

Defines a Panel Settings asset that instantiates a panel at runtime. The panel makes it possible for Unity to display UXML-file based UI in the Game view.
    We created a "Panel Settings" with default Unity values
      No need to update these as the default values work fine
      Digging into the weeds of each field in Panel Settings is a bit overkill for this gitbook, but if you're curious we recommend that you check out the documentation linked above
    Drag "PanelSettings" into the "Panel Settings" field in the UI Document component found in Inspector when TitleScreenUI is selected in Hierarchy
Dragging our PanelSettings to the UI Document Component
    Right-click in our UI folder, hover over Create, navigate down to UI Toolkit, and select "UI Document" and name the file TitleScreenManager
      This will be our parent uxml of our NavigationScene UI
    Drag it to the Source Asset field of the UI Document component found in Inspector when TitleScreenUI is selected in Hierarchy
Creating TitleScreenManager and dragging to SourceAsset field
    Now create your next 4 UI Documents (right-click in UI folder, Create, hover over UI Toolkit, and select UI Document, naming each individual UI Document as follows):
      TitleScreen
      HostGameScreen
      JoinGameScreen
      ManualConnectScreen
Creating uxmls for our next 4 views
    If you expand each of the uxmls (UI Documents) you will notice that they each have something called inlineStyle
      We will have a shared USS that will allow us to share stylings across views
      But a view might have some stylings that are specific to that one particular view and to no other views; these stylings are called "inline" styles
        (AKA styles that are part of the document but do not come from a separate USS sheet)
    For now, we're not going to paste in any code snippets into these uxmls we just made right now
    Now let's create our 4 custom Visual Elements (cVEs)
      Again, they will have the exact same names as the uxml files. Please try not to get confused!
    To make each of the 4 cVEs, just right-click in the UI folder > Create > C# Script and name each file according to the four bullet points below, pasting the code snippet underneath into each cs files:
    TitleScreenManager
1
using UnityEngine;
2
using UnityEngine.UIElements;
3
4
public class TitleScreenManager : VisualElement
5
{
6
7
public new class UxmlFactory : UxmlFactory<TitleScreenManager, UxmlTraits> { }
8
9
public TitleScreenManager()
10
{
11
this.RegisterCallback<GeometryChangedEvent>(OnGeometryChange);
12
}
13
14
void OnGeometryChange(GeometryChangedEvent evt)
15
{
16
17
18
this.UnregisterCallback<GeometryChangedEvent>(OnGeometryChange);
19
}
20
}
Copied!
    HostGameScreen
1
using UnityEngine;
2
using UnityEngine.UIElements;
3
4
public class HostGameScreen : VisualElement
5
{
6
7
public new class UxmlFactory : UxmlFactory<HostGameScreen, UxmlTraits> { }
8
9
public HostGameScreen()
10
{
11
this.RegisterCallback<GeometryChangedEvent>(OnGeometryChange);
12
}
13
14
void OnGeometryChange(GeometryChangedEvent evt)
15
{
16
17
18
this.UnregisterCallback<GeometryChangedEvent>(OnGeometryChange);
19
}
20
}
Copied!
    JoinGameScreen
1
using UnityEngine;
2
using UnityEngine.UIElements;
3
4
public class JoinGameScreen : VisualElement
5
{
6
7
public new class UxmlFactory : UxmlFactory<JoinGameScreen, UxmlTraits> { }
8
9
public JoinGameScreen()
10
{
11
this.RegisterCallback<GeometryChangedEvent>(OnGeometryChange);
12
}
13
14
void OnGeometryChange(GeometryChangedEvent evt)
15
{
16
17
18
this.UnregisterCallback<GeometryChangedEvent>(OnGeometryChange);
19
}
20
}
Copied!
    ManualConnectScreen
1
using UnityEngine;
2
using UnityEngine.UIElements;
3
4
public class ManualConnectScreen : VisualElement
5
{
6
7
public new class UxmlFactory : UxmlFactory<ManualConnectScreen, UxmlTraits> { }
8
9
public ManualConnectScreen()
10
{
11
this.RegisterCallback<GeometryChangedEvent>(OnGeometryChange);
12
}
13
14
void OnGeometryChange(GeometryChangedEvent evt)
15
{
16
17
18
this.UnregisterCallback<GeometryChangedEvent>(OnGeometryChange);
19
}
20
}
Copied!
    These are the custom Visual Elements (cVEs) we will nest in our UXMLs
    In the code for each, you will notice that we work within 3 boilerplate "section" (for lack of a better word) to build our UI. They are as follows:
      UxmlFactory
        (this will allow us to read from the UXML we are nested in so we can add functionality)
        We will not alter this
      this.RegisterCallback(OnGeometryChange)
        We will not alter this
      OnGeometryChange(GeometryChangedEvent evt)
        This runs each time the layout is updated
        Here we will assign any visual elements we want to interact with and register any callbacks
        Think of it like Create() or OnCreate()
We have named our custom Visual Elements (cVEs) after the uxmls they will be nested in.
FYI: you are able to change the name of your cVEs and nest them anywhere; the name is not a dependency for working with uxml.
However, if you do change the name you must change it in the 3 places you see the name used in the files above:
    Where the public class is defined (at the top)
    Where you define the uxml factory
    The constructor that contains registering the callback OnGeometryChange
Again, if you change the name of a cVE, the uxmls will not automatically pick up this change. Instead, you will need to manually update the names in the uxml files themselves.
We at Moetsi like to match names as a rule of thumb (although it may seem confusing) to provide clarity on exactly what each cVE should do. We don't find it too confusing because the uxmls and cVEs are different file types so the little iconography next to the file names symbolize the difference between the two.

Class VisualElement.UxmlFactory

Instantiates a VisualElement using the data read from a UXML file.

GeometryChangedEvent

Event sent after layout calculations, when the position or the dimension of an element changes. This event cannot be cancelled, it does not trickle down, and it does not bubble up.
Creating our 4 custom Visual Elements (cVEs)
    Now that we have created our uxmls and cVEs let's open up UI Builder
      Navigate to "Window', select "UI Toolkit", then choose "UI Builder"
Opening up UI Builder
    We are now ready to to structure our components
      You might not have "TitleScreenManager" already available in the Hierarchy when you open UI Builder, don't worry we open it up as our next step below
We created our UI components in this section and we are prepared to structure them in the next section
    We created NavigationScene
    We added a TitleScreenUI GameObject
    We added Event System (UI Toolkit) and UI Document
    We created uxmls
      TitleScreenManager
      TitleScreen
      HostGameScreen
      JoinGameScreen
      ManualConnectScreen
    We created custom Visual Elements (cVEs)
      TitleScreenManager
      HostGameScreen
      JoinGameScreen
      ManualConnectScreen
    We navigated to UI Builder

Working with UI Builder

We are going to use the UI Builder to put our different components together and to also add additional standard Visual Elements. In the next section we will also do styling in the UI Builder.
You will notice that there is no way to create new Visual Elements through the UI Builder. This is why we started this section by creating those items first. It is generally a good idea to plan out your views and structure before working with UI Builder to make construction a bit easier.

The main UI Builder window

    1.
    StyleSheets: Manage StyleSheets and USS Selectors to share styles across UI Documents (UXML) and elements.
    2.
    Hierarchy: Select, reorder, reparent, cut, copy, paste, delete elements in the UI hierarchy of your document.
    3.
    Library: Create new elements or instance other UI Documents (UXML).
    4.
    Viewport: See what your UI Document (UXML) looks like and edit elements visually directly on the Canvas.
    5.
    Code Previews: See what the UI Builder is creating as text for both the UI Document (UXML) and the StyleSheets (USS).
    6.
    Inspector: Use it to change the attributes and style properties of the selected element or USS selector.
It's a good idea to watch Unity's UI Builder video to get an overview of the different parts of UI Builder. This gitbook will touch on most aspects of UI Builder, but to get a more exhaustive understanding we recommend watching Unity's run-through of the entire system.
    While UI Builder is open, navigate to the "Library" section and take a look at what exists on the "Standard" tab
      Standard Visual Elements are broken out into two sections:
        Containers
        Controls
      We will use these Standard Visual Element to build our UI in UI Builder
    Now click on the Project tab
      This tab is broken out into
        UI Documents (UXML)
        Custom Controls (C#) (Our custom Visual Elements, cVEs)
    Expand the UI folder in the Assets folder and notice the uxmls we created
    Scroll to TitleScreenManager, hover over, and click on the icon that appears on the right
    We have now loaded our TitleScreenManager uxml into our Hierarchy
      Be careful not to double-click any items in project as that actually loads into the Hierarchy (unless you intend to load the item you double clicked into your current Hierarchy)
    Also notice that you cannot "open" our cVEs like you can our uxmls
      There is no icon that appears when you hover over a cVE
      In order to update the contents of our cVEs, we must go into the actual file
Navigating UI Builder to find our uxmls and custom Visual Elements
    Drag TitleScreenManager.cs from Custom Controls into the Hierarchy
    Click on TitleScreenManager.uxml in the Hierarchy and hit save
      Generally, always click on the uxml and save after making any change
        UI Builder is still a bit wonky, so it's is better to be safe than sorry and a necessary step to saving is selecting the uxml in the Hierarchy before hitting save
Dragging our custom Visual Element into our uxml
    We now have our custom Visual Element (cVE) nested in our uxml
      Woo! Our ScreenManager is all set up!
      FYI: Having a "ScreenManager all set up" is when there is a parent UXML + a child cVE, which will control all other children uxmls/Visual Elements
    Click on our TitleScreenManager cVE in Hierarchy and notice how the large blue highlighted area shrinks down to a line when we click from the TitleScreenManager uxml to the cVE
      You may need to expand the window to see this
      This is because our cVE is currently styled to consume only as much "room" on the screen as its contents take up
        And because our cVE is empty, the styled area shrinks
Seeing how the areas covered by the uxml and cVE differ
It is important to note that the size of the TitleScreenManager uxml in UI Builder does not have a connection to the size the game will be rendered at.
The uxml will take as much space as exists (similar to view height and view width in Web Development).
By resizing this uxml canvas, we can test how the UI will react to different screen sizes/resolutions.
Within the Viewport pane, you can find the Canvas, a floating re-sizable edit-time container that contains a live version of the UI Document (UXML) being edited. If you can't see it, try clicking on the Fit Canvas button in the Viewport toolbar to bring it into view. Any settings related to the Canvas, like its size, are not saved as part of the UI Document (UXML) but will be remembered (using an internal separate settings file) for the next time you open the same UI Document (UXML).
You can directly resize the Canvas inside the Viewport by dragging its edges or corners. For exact sizing, you can click on the header of the Canvas to access its settings via the Inspector pane, where you will see fields for Canvas height and width. In the same section, you can also lock the Canvas size to the size of the Unity Game Window using the Match Game View checkbox to better match a runtime UI environment:
With the Canvas selected, in the Inspector, you can change the Canvas background to make editing the UI in context easier. You can set it to be a solid color, a specific texture (ie. a mockup from a UI Designer), or a live view from a Camera in the currently open Unity Scene:
    Maximize the UI Builder to make it easier to navigate
    Click on TitleScreenManager uxml and resize it to see that it the blue highlighted area always takes up the size of the canvas
      Type in values in Canvas Size in the Inspector to see the canvas resize
      Drag the sides of the canvas and notice how the "Canvas Size" values in the Inspector change
    Hit "Fit Canvas" in the top and it will automatically set to be contained within the Viewport
Resizing the canvas and seeing the effects in the Inspector and vice versa
    We aren't going to dive much deeper into the functionality of the UI Builder because it's so thoroughly explained in Unity's UI Builder talk
    We will move on and focus on how to make certain functionalities work
    Click on our TitleScreenManager cVE and in the Inspector, type TitleScreenManager in the "Name" field
Naming the TitleScreenManager cVE
    In "StyleSheets" (top left) hit the plus sign and select "Create new USS"
    Create a new USS named "TitleScreenUI" in the "UI" folder (you might need to expand the Finder window in order to navigate to the UI folder)
    Save TitleScreenUI.uss and TitleScreenManager.uxml (select the uxml and save)
      We will not continue repeating ourselves in this section about saving both the uxml and USS again and again, so just please do it often
      If you don't save often, sometimes UI Builder can get confused
Creating TitleScreenUI.uss in Assets/UI
    Now select the TitleScreenManager cVE and in the Inspector navigate to "Flex"
      Update "Grow" to 1
    Notice how the highlighted area now encompasses the entire canvas
      We have "styled" our TitleScreenManager cVE to "grow" to the entire canvas
    Now under "StyleSheet" in the Inspector type ".screen" into the Style Class List input field and then click "Extract Inlined Styles to New Class"
      Nice! We just made a new "class" of style called ".screen"
      We can now apply this style to other Visual Elements and it will update the Visual Element's styling
      We will use this class for all our "screens"
Creating class ".screen"
    Now expand TitleScreenUI.uss in StyleSheets
Seeing our new class in TitleScreenUI.uss
    Here is where we see that the UI Builder has automatically put our extracted class in our USS
      Thanks, UI Builder!
    Now let's drag our 4 other uxmls into our TitleScreenManager cVE
      They should be nested within the cVE
Nesting our 4 uxmls in our TitleScreenManager cVE
We now have our initial setup of our TitleScreenManager
    We nested our TitleScreenManager cVE within the uxml
    We created TitleScreenUI USS
    We created a .screen class
    We nested TitleScreen, HostGameScreen, JoinGameScreen, ManualConnectScreen uxmls in our TitleScreenManager cVE

Adding Visual Elements and switching views

We are going to add Visual Elements to our nested uxmls (TitleScreen, HostGameScreen, JoinGameScreen, ManualConnectScreen). While TitleScreenManager.uxml is the focus in our Hierarchy, it is not possible to add Visual Elements to the nested uxmls. We will quickly show you what we mean.
    In UI Builder, navigate to the Library, select the Standard tab, and drag a VisualElement into our nested TitleScreen uxml
    Save TitleScreenManager.uxml
    Now go to Library, then to the Project tab, and open the TitleScreen uxml
    No VisualElement!
    That is because we did not insert the VisualElement into the actual TitleScreen uxml file
      It is part of the TitleScreenManager uxml (because it was the focus in our Hierarchy)
    Delete the VisualElement and save
Adding VisualElement does not appear in TitleScreen uxml
    TitleScreenManager.uxml is the file that's actually keeping track of this new VisualElement
      This approach of not actually nesting the VisualElement in the child uxml can work, but in this gitbook we want to have self-contained files for separation of concerns
    So let's take a brief look at the different ways we can edit these nested uxmls
    Right-click on TitleScreen in TitleScreenManager's Hierarchy and notice the options on the bottom:
      Open in UI Builder
      Open as Sub Document
      Open as Sub Document in Place
    We will be editing our uxmls through the "Open in UI Builder" option
      This allows you to focus on the exact screen you are working on
      This will open the uxml in the same way that navigating to Library > Project > UI Documents > uxml selection would
      You can use the other options to edit while in the context of the greater Hierarchy but we have found it easier to focus on one view at a time when doing anything other than just minor touchups
    Click on "Open in UI Builder"
Checking out different ways to edit a uxml
    The uxml will take up as much space as its parent
      The parent of TitleScreenManager uxml is the actual display so it will take up as much space as the display
      The parent of TitleScreen is our cVE (TitleScreenManager) which we have made take up the entire display as well (through the .screen class)
    We are going to add a VisualElement that takes up the entire screen to this uxml so that we can make full use of the display when adding our content
      This might seem a little confusing at first but we want to take up the whole area with a parent element
        We just made a full screen container, why do we need another one?!
      Think of it as turning on the lights to a room
      We want the light everywhere so we can place our objects relative to each other knowing the boundaries of the room
      If we were to place our items in the room in the dark, we will not be able to control where they are relative to boundaries
      (Eh, that wasn't our best analogy. If you have a better one please reach out in the Moetsi Discord!)
    Drag a standard VisualElement to the Hierarchy
    Change the VisualElement's name to "screen"
      Instead of changing the name when the item is selected in Inspector, you can also do this from the Hierarchy by renaming the element "#screen"
        The "#" is a convention from CSS (web development)
    In StyleSheets (top left of UI Builder), click the "+" and "Add Existing USS" and select "TitleScreenUI.uss"
    When the #screen VisualElement is selected in Hierarchy, go to Inspector and under StyleSheet type in ".screen" in the Style Class List field. Click "Add Style Class to List"
      This will add ".screen" from TitleScreenUI.uss to "#screen"
Adding "screen", TitleScreenUI USS, and adding .screen class
    We can see that screen now has the same styling as our .screen class and grows to take up space
    We want to be able to differentiate screens so let's change the background
    Select "#screen" and in the Inspector scroll down to "Background" and change the color to a blueish color (or whatever color you like)
    Next, let's add 3 buttons as children of screen
    Find the Button in the Standard tab under Controls, and drag three of them under #screen in Hierarchy as children
      Name = host-local-button
        Text: Host game
      Name = join-local-button
        Text: Join game
      Name = manual-connect-button
        Text: Manually connect
Setting background color and adding 4 buttons
    Now we will change the backgrounds and add a button to each of the other views as well
      We will navigate to one of the 3 other views from TitleScreen using TitleScreen's 3 buttons
      The other views will have a button back to TitleScreen
    For the other 3 screens we will not add a standard VisualElement as we did for TitleScreen, we will add our cVEs
      We did not need to add a cVE for TitleScreen to add callbacks to the buttons because we will use the cVE TitleScreenManager
        If this is still a bit confusing, please bare with us and once we start adding callbacks it should make more sense
        Hit save!
    Open up HostGameScreen by navigating to the Project tab in Library and clicking the open icon when hovering over it:
      Hit + under StyleSheets and click "Add Existing USS," select TitleScreenUI USS
      Drag HostGameScreen from "Custom Controls" in Library into the Hierarchy
      Add the .screen class to the HostGameScreen cVE (found in the StyleSheet section, type ".screen" and click Add Style Class to List)
      Name the cVE "HostGameScreen" (by typing in HostGameScreen into the "Name" field in Inspector)
Adding USS, class, and name to HostGameScreen
    Next
      Make the background greenish
      Add a Label (drag one from Controls under Standard tab in Library)
        Don't name the Label
        Text = "Host Screen"
      Add a button
        Name = "back-button"
        text = "Back"
Adding background, label, and button to HostGameScreen
    We have our basic (albeit not very pretty) HostGameScreen
      You might be wondering why didn't we name the label?
        Or not, but we are going to tell you anyway!
      In order to reference VisualElements in our custom Visual Elements (cVEs) they must have names to identify them (like an id)
      If we don't plan on interacting with an element, then there is no real functional need to name them
        Other than to make the Hierarchy a bit more clear to know what is going on
          Which we will eventually do in the next section, "Styling a View," but it's too much to do right now
    Next up open JoinGameScreen
      Add TitleScreenUI USS
      Drag JoinGameScreen from "Custom Controls" in Library into the Hierarchy
      Add the .screen class to the JoinGameScreen cVE
      Name the cVE "JoinGameScreen"
Setting up JoinGameScreen
    Next
      Make the background orange-ish
      Add a Label
        Text = "Join Screen"
      Add a button
        Name = "back-button"
        text = "Back"
Adding a background, label, and button to JoinGameScreen
    One more screen to go, ManualConnectScreen
    Open ManualConnectScreen
      Add TitleScreenUI USS
      Drag ManualConnectScreen from "Custom Controls" in Library into the Hierarchy
      Add the .screen class to the ManualConnectScreen cVE
      Name the cVE "ManualConnectScreen"
Setting up ManualConnectScreen
    Next
      Make the background purplish
      Add a Label
        Text = "Manual Connect Screen"
      Add a button
        Name = "back-button"
        text = "Back"
Setting up background and buttons to ManualConnectScreen
    Now let's navigate to TitleScreenManager
Navigating to TitleScreenManager and seeing a mess
    What is going on why is it when we click on each of our nested uxmls the highlighted area is so small?
      We have not added the .screen class to all the uxmls themselves
        Just the Visual Elements within them
        Let's fix that
    Add the .screen class to each of the nested uxmls
Adding the .screen class to all the uxmls
    Okay so they are not tiny any more, they grow to take the space but now there are 4 equally spaced screens
      We want to only display one screen at a time
    Click on HostGameScreen in the Hierarchy and in the Inspector navigate to the Display section and change the Display field from "flex" to "none" (you need to hover over the little icons to know which one is "flex" and which one is "none")
    Repeat for JoinGameScreen and ManualConnectScreen
Changing screen Display values to "none"
    We have our single TitleScreen visible with 3 buttons that will take us to the other views
    One more thing to checkout in UI Builder:
      At the bottom you can pull up "UXML Preview" and "USS Preview" and see that what we created in TitleScreenManager.uxml is being actually saved as code
Examining UXML Preview and USS Preview
    This illustrates that UI Builder is almost like an "interpreter" of the uxml and USS we are creating and all the changes we make are saved and reflected in these files
    In the next step we will add callbacks to the buttons we created to change the display values of different screens
Now now have our NavigationScene UI set up
    We added TitleScreenUI USS to each uxml
    We added a .screen class, background, name, buttons and labels to each view
    We added the .screen class to each uxml
    We updated the Display property in the inspector to "none" of
      HostGameScreen
      JoinGameScreen
      ManualConnectScreen

Adding callbacks to our UI

Now that we have our screens and buttons set up, we want to add logic to be able to toggle between different views.
The TitleScreenManager cVE will handle adding callbacks to the TitleScreen uxml buttons and the back buttons that return to the uxml. This way we have a single cVE that we know is in charge of displaying views (separation of concerns).
Our TitleScreenManager uxml/VE approach
    Close out of UI Builder and open up TitleScreenManager.cs (the cVE)
    We are going to need to declare 4 variables for our 4 views at the top
      TitleScreen
      HostGameScreen
      JoinGameScreen
      ManualConnectScreen
    Then we are going to have to "query" our nested children by name, and assign them to those variables
    Once we have our views, we will then query within those views to find our buttons and assign callbacks
    Finally, we will create functions to hide and display views when different buttons are pressed
    Paste the code snippet below into TitleScreenManager.cs:
1
using System.Collections;
2
using System.Collections.Generic;
3
using UnityEngine;
4
using UnityEngine.UIElements;
5
6
public class TitleScreenManager : VisualElement
7
{
8
VisualElement m_TitleScreen;
9
VisualElement m_HostScreen;
10
VisualElement m_JoinScreen;
11
VisualElement m_ManualConnectScreen;
12
13
public new class UxmlFactory : UxmlFactory<TitleScreenManager, UxmlTraits> { }
14
15
public TitleScreenManager()
16
{
17
this.RegisterCallback<GeometryChangedEvent>(OnGeometryChange);
18
}
19
20
void OnGeometryChange(GeometryChangedEvent evt)
21
{
22
m_TitleScreen = this.Q("TitleScreen");
23
m_HostScreen = this.Q("HostGameScreen");
24
m_JoinScreen = this.Q("JoinGameScreen");
25
m_ManualConnectScreen = this.Q("ManualConnectScreen");
26
27
m_TitleScreen?.Q("host-local-button")?.RegisterCallback<ClickEvent>(ev => EnableHostScreen());
28
m_TitleScreen?.Q("join-local-button")?.RegisterCallback<ClickEvent>(ev => EnableJoinScreen());
29
m_TitleScreen?.Q("manual-connect-button")?.RegisterCallback<ClickEvent>(ev => EnableManualScreen());
30
31
m_HostScreen?.Q("back-button")?.RegisterCallback<ClickEvent>(ev => EnableTitleScreen());
32
m_JoinScreen?.Q("back-button")?.RegisterCallback<ClickEvent>(ev => EnableTitleScreen());
33
m_ManualConnectScreen?.Q("back-button")?.RegisterCallback<ClickEvent>(ev => EnableTitleScreen());
34
35
this.UnregisterCallback<GeometryChangedEvent>(OnGeometryChange);
36
}
37
38
public void EnableHostScreen()
39
{
40
m_TitleScreen.style.display = DisplayStyle.None;
41
m_HostScreen.style.display = DisplayStyle.Flex;
42
m_JoinScreen.style.display = DisplayStyle.None;
43
m_ManualConnectScreen.style.display = DisplayStyle.None;
44
45
}
46
47
public void EnableJoinScreen()
48
{
49
m_TitleScreen.style.display = DisplayStyle.None;
50
m_HostScreen.style.display = DisplayStyle.None;
51
m_JoinScreen.style.display = DisplayStyle.Flex;
52
m_ManualConnectScreen.style.display = DisplayStyle.None;
53
}
54
55
public void EnableManualScreen()
56
{
57
m_TitleScreen.style.display = DisplayStyle.None;
58
m_HostScreen.style.display = DisplayStyle.None;
59
m_JoinScreen.style.display = DisplayStyle.None;
60
m_ManualConnectScreen.style.display = DisplayStyle.Flex;
61
}
62
63
public void EnableTitleScreen()
64
{
65
m_TitleScreen.style.display = DisplayStyle.Flex;
66
m_HostScreen.style.display = DisplayStyle.None;
67
m_JoinScreen.style.display = DisplayStyle.None;
68
m_ManualConnectScreen.style.display = DisplayStyle.None;
69
}
70
71
}
72
Copied!
Our TitleScreenManager working and allowing us to switch between views
We now have our TitleScreenManager functioning
    We updated our TitleScreenManager custom Visual Element to provide callbacks and functions when clicked
Github branch link:
git clone https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/ git checkout 'Creating-a-ScreenManager'
Last modified 6mo ago