Version: 2021.3
言語: 日本語
カスタムエディターウィンドウの作成
カスタムエディターウィンドウ内にドラッグアンドドロップ UI を作成する

ランタイム用タブメニューの作成

タブ付きメニューは、ビデオゲームやアプリケーションの UI でよく見られます。UI Toolkit を使用すると、カスタムエディターウィンドウやランタイムにタブ付きメニューを作成することができます。この例では、サンプルシーンにタブ付きメニューを作成する方法を説明します。

例の概要

この例では、サンプルシーンにメニューを加えます。メニューには 3 つのタブがあります。各タブには、特定のコンテンツが表示されます。タブをクリックすると、そのタブに関連するコンテンツのみが表示されます。

タブメニューのプレビュー
タブメニューのプレビュー

タブ付きコンテンツを作成するには、メニューの要素、スタイル、ロジックを定義する必要があります。

この例で作成するすべてのファイルは、GitHub リポジトリ にあります。

要件

This guide is for developers who are familiar with Unity, UI Toolkit, Flexbox, and C# scripting.

This guide references the following concepts:

タブメニューの要素を定義する

UI Builder を使用して、メニューに 2 つのセクション (タブ用とタブのコンテンツ用) を作成します。これらのセクションに、3 つのタブ要素と 3 つのタブコンテンツ要素を作成します。

  1. Create a project in Unity Editor using any template.

  2. GameObject > UI Toolkit > UI Document の順にクリックして、サンプルシーンに UI ドキュメントを加えます。

  3. Create a folder in Assets called TabbedMenu to store all your files.

  4. In the TabbedMenu folder, create a UI Document called TabbedMenu.uxml.

  5. Add the UXML to your UI Document by selecting the UIDocument in the SampleScene and dragging TabbedMenu.uxml to Source Asset in the UI Document section in the Inspector.

  6. Open TabbedMenu.uxml using the UI Builder.

  7. Add two VisualElements called tabs and tabContent under the root.

  8. Under tabs, add three Label controls and give them the following Label texts:

    • London
    • Paris
    • Ottawa
  9. tabContent の下に 3 つのラベルコントロールを加え、それらに以下のラベルテキストを設定します。

    • London is the capital city of England (London は英国の首都)
    • Paris is the capital of France (Paris はフランスの首都)
    • Ottawa is the capital of Canada (Ottawa はカナダの首都)
  10. タブの内容をタブに関連付けるため、この例ではラベル名に同じプレフィックスと異なるサフィックスを使用しています。各タブ名には Tab というサフィックスを、各タブコンテンツには Content というサフィックスを付けています。タブのラベル名とコンテンツのラベル名を以下のように設定します。

    • LondonTab
    • ParisTab
    • OttawaTab
    • LondonContent
    • ParisContent
    • OttawaContent

Your UI Builder Hierarchy should look like the following:

UI Builder の Hierarchy
UI Builder の Hierarchy

タブメニュースタイルを定義する

USS を使って、タブとタブコンテンツのレイアウトを定義します。タブとタブコンテンツは、好きなようにスタイルを設定することができます。この例では、タブを一列に並べ、その上にタブコンテンツを配置しています。また、選択されたタブの背景色を追加し、選択されていないタブの内容を非表示にします。

  1. In the TabbedMenu folder, create a stylesheet called TabbedMenu.uss.

  2. TabbedMenu.uss を開き、以下のスタイルルールを加えます。

    /* Style for tabs */
    #tabs {
        flex-basis: 10%;
        flex-direction: row;
        background-color: rgb(229, 223, 223);
        font-size: 12px;
        -unity-font-style: bold;
        font-size: 14px;
    }
    
    /* Sets each label in tabs to have the same size. */
    .tab {
        flex-grow: 1;
    }
    
    /* Adds background color for the selected tab */
    .currentlySelectedTab {
        background-color: rgb(173, 166, 166);
    }
    
    /* Style for tabContent */
    #tabContent {
        flex-basis: 90%;
        background-color: rgb(255, 255, 255);
        font-size: 20px;
    }
    
    /* Hides the unselected tab content */
    .unselectedContent {
        display: none;
    }
    
  3. UI Builder で TabbedMenu.uxml を開きます。

  4. Add Existing USS をクリックし、TabbedMenu.uss を選択します。

  5. 作成したスタイルを UI コントロールに適用します。

    • tabs の下にある各ラベルに .tab を適用します。
    • .currentlySelectedTabLondonTab に適用します。
    • .unselectedContentParisContentOttawaContent に適用します。

The finished TabbedMenu.uxml should look like the following:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
   /* Your src might look different. If you save your UXML in UI Builder, USS file is referenced by the file location, fileID and guid. */
   <Style src="TabbedMenu-style.uss" />
   <ui:VisualElement name="tabs">
      <ui:Label name="LondonTab" text="London" class="tab currentlySelectedTab" />
      <ui:Label name="ParisTab" text="Paris" class="tab" />
      <ui:Label name="OttawaTab" text="Ottawa" class="tab" />
   </ui:VisualElement>
   <ui:VisualElement name="tabContent">
      <ui:Label text="London is the capital city of England" name="LondonContent" />
      <ui:Label text="Paris is the capital of France" name="ParisContent" class="unselectedContent" />
      <ui:Label text="Ottawa is the capital of Canada" name="OttawaContent" class="unselectedContent" />
   </ui:VisualElement>
</ui:UXML>

タブメニューのロジックを定義する

Create the C# scripts that change the displayed tab content. When a user clicks a tab, the tab’s content displays and the current content hides.

  1. In the TabbedMenu folder, create the following two C# script files:

    • TabbedMenu.cs: Attaches the tabbed menu logic to the game.
    • TabbedMenuController.cs: Defines the tab selection logic.
  2. Add TabbedMenu.cs as a component to the UI Document by selecting the UIDocument in the SampleScene and dragging TabbedMenu.cs to Add Component button in the Inspector.

  3. Open TabbedMenu.cs and replace with the following code:

    using UnityEngine;
    using UnityEngine.UIElements;
    
    //Inherits from class `MonoBehaviour`. This makes it attachable to a game object as a component.
    public class TabbedMenu : MonoBehaviour
    {
        private TabbedMenuController controller;
    
        private void OnEnable()
        {
            UIDocument menu = GetComponent<UIDocument>();
            VisualElement root = menu.rootVisualElement;
    
            controller = new(root);
    
            controller.RegisterTabCallbacks();
        }
    }
    
  4. Open TabbedMenuController.cs and replace with the following code:

    using UnityEngine.UIElements;
    
    public class TabbedMenuController
    {
        /* Define member variables*/
        private const string tabClassName = "tab";
        private const string currentlySelectedTabClassName = "currentlySelectedTab";
        private const string unselectedContentClassName = "unselectedContent";
        // Tab and tab content have the same prefix but different suffix
        // Define the suffix of the tab name
        private const string tabNameSuffix = "Tab";
        // Define the suffix of the tab content name
        private const string contentNameSuffix = "Content";
    
        private readonly VisualElement root;
    
        public TabbedMenuController(VisualElement root)
        {
            this.root = root;
        }
    
        public void RegisterTabCallbacks()
        {
            UQueryBuilder<Label> tabs = GetAllTabs();
            tabs.ForEach((Label tab) => {
                tab.RegisterCallback<ClickEvent>(TabOnClick);
            });
        }
    
        /* Method for the tab on-click event: 
    
           - If it is not selected, find other tabs that are selected, unselect them 
           - Then select the tab that was clicked on
        */
        private void TabOnClick(ClickEvent evt)
        {
            Label clickedTab = evt.currentTarget as Label;
            if (!TabIsCurrentlySelected(clickedTab))
            {
                GetAllTabs().Where(
                    (tab) => tab != clickedTab && TabIsCurrentlySelected(tab)
                ).ForEach(UnselectTab);
                SelectTab(clickedTab);
            }
        }
        //Method that returns a Boolean indicating whether a tab is currently selected
        private static bool TabIsCurrentlySelected(Label tab)
        {
            return tab.ClassListContains(currentlySelectedTabClassName);
        }
    
        private UQueryBuilder<Label> GetAllTabs()
        {
            return root.Query<Label>(className: tabClassName);
        }
    
        /* Method for the selected tab: 
           -  Takes a tab as a parameter and adds the currentlySelectedTab class
           -  Then finds the tab content and removes the unselectedContent class */
        private void SelectTab(Label tab)
        {
            tab.AddToClassList(currentlySelectedTabClassName);
            VisualElement content = FindContent(tab);
            content.RemoveFromClassList(unselectedContentClassName);
        }
    
        /* Method for the unselected tab: 
           -  Takes a tab as a parameter and removes the currentlySelectedTab class
           -  Then finds the tab content and adds the unselectedContent class */
        private void UnselectTab(Label tab)
        {
            tab.RemoveFromClassList(currentlySelectedTabClassName);
            VisualElement content = FindContent(tab);
            content.AddToClassList(unselectedContentClassName);
        }
    
        // Method to generate the associated tab content name by for the given tab name
        private static string GenerateContentName(Label tab) =>
            tab.name.Replace(tabNameSuffix, contentNameSuffix);
    
        // Method that takes a tab as a parameter and returns the associated content element
        private VisualElement FindContent(Label tab)
        {
            return root.Q(GenerateContentName(tab));
        }
    }
    

Go back to Unity and enter Play mode. You should see the content change when you click a new tab.


Tabbed menu example added in Unity 2021.2 NewIn20212

カスタムエディターウィンドウの作成
カスタムエディターウィンドウ内にドラッグアンドドロップ UI を作成する