Version: 2021.3
言語: 日本語
カスタムコントロール
Create a radial progress indicator

スライドトグルカスタムコントロールの作成

Version: 2021.2

この例では、“スイッチのような” トグルを作成する方法を説明します。

例の概要

この例では、マウス、キーボード、ゲームパッド、その他のデバイスでユーザーが切り替えできるトグルというカスタムコントロールを作成します。このコントロールには、トグルが何を表しているかを説明するラベルも設定します。

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

要件

This is an advanced example for developers familiar with Unity Editor, UI Toolkit, and C# scripting. Unity recommends that you have a basic understanding of the following concepts:

スライドトグルの作成とスタイル設定

C# スクリプトでスライドトグルのクラスを作成し、USS ファイルでスタイルを設定します。

  1. 3D テンプレートで Unity プロジェクトを作成します。この例では、3D テンプレートの方が高い視覚効果を得られます。ただし、どのテンプレートを使っても構いません。

  2. ファイルを保存するために slide-toggle という名前のフォルダーを作成します。

  3. In the SlideToggle folder, create a C# script named SlideToggle.cs.

  4. テキストエディターで SlideToggle.cs スクリプトを開き、そのコンテンツを下のコードに置き換えます。

    using UnityEngine;
    using UnityEngine.UIElements;
    
    namespace MyUILibrary
    {
        // Derives from BaseField<bool> base class. Represents a container for its input part.
        public class SlideToggle : BaseField<bool>
        {
            public new class UxmlFactory : UxmlFactory<SlideToggle, UxmlTraits> { }
    
            public new class UxmlTraits : BaseFieldTraits<bool, UxmlBoolAttributeDescription> { }
    
            // In the spirit of the BEM standard, the SlideToggle has its own block class and two element classes. It also
            // has a class that represents the enabled state of the toggle.
            public static readonly new string ussClassName = "slide-toggle";
            public static readonly new string inputUssClassName = "slide-toggle__input";
            public static readonly string inputKnobUssClassName = "slide-toggle__input-knob";
            public static readonly string inputCheckedUssClassName = "slide-toggle__input--checked";
    
            VisualElement m_Input;
            VisualElement m_Knob;
    
            // Custom controls need a default constructor. This default constructor calls the other constructor in this
            // class.
            public SlideToggle() : this(null) { }
    
            // This constructor allows users to set the contents of the label.
            public SlideToggle(string label) : base(label, null)
            {
                // Style the control overall.
                AddToClassList(ussClassName);
    
                // Get the BaseField's visual input element and use it as the background of the slide.
                m_Input = this.Q(className: BaseField<bool>.inputUssClassName);
                m_Input.AddToClassList(inputUssClassName);
                Add(m_Input);
    
                // Create a "knob" child element for the background to represent the actual slide of the toggle.
                m_Knob = new();
                m_Knob.AddToClassList(inputKnobUssClassName);
                m_Input.Add(m_Knob);
    
                // There are three main ways to activate or deactivate the SlideToggle. All three event handlers use the
                // static function pattern described in the Custom control best practices.
    
                // ClickEvent fires when a sequence of pointer down and pointer up actions occurs.
                RegisterCallback<ClickEvent>(evt => OnClick(evt));
                // KeydownEvent fires when the field has focus and a user presses a key.
                RegisterCallback<KeyDownEvent>(evt => OnKeydownEvent(evt));
                // NavigationSubmitEvent detects input from keyboards, gamepads, or other devices at runtime.
                RegisterCallback<NavigationSubmitEvent>(evt => OnSubmit(evt));
            }
    
            static void OnClick(ClickEvent evt)
            {
                var slideToggle = evt.currentTarget as SlideToggle;
                slideToggle.ToggleValue();
    
                evt.StopPropagation();
            }
    
            static void OnSubmit(NavigationSubmitEvent evt)
            {
                var slideToggle = evt.currentTarget as SlideToggle;
                slideToggle.ToggleValue();
    
                evt.StopPropagation();
            }
    
            static void OnKeydownEvent(KeyDownEvent evt)
            {
                var slideToggle = evt.currentTarget as SlideToggle;
    
                // NavigationSubmitEvent event already covers keydown events at runtime, so this method shouldn't handle
                // them.
                if (slideToggle.panel?.contextType == ContextType.Player)
                    return;
    
                // Toggle the value only when the user presses Enter, Return, or Space.
                if (evt.keyCode == KeyCode.KeypadEnter || evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.Space)
                {
                    slideToggle.ToggleValue();
                    evt.StopPropagation();
                }
            }
    
            // All three callbacks call this method.
            void ToggleValue()
            {
                value = !value;
            }
    
            // Because ToggleValue() sets the value property, the BaseField class dispatches a ChangeEvent. This results in a
            // call to SetValueWithoutNotify(). This example uses it to style the toggle based on whether it's currently
            // enabled.
            public override void SetValueWithoutNotify(bool newValue)
            {
                base.SetValueWithoutNotify(newValue);
    
                //This line of code styles the input element to look enabled or disabled.
                m_Input.EnableInClassList(inputCheckedUssClassName, newValue);
            }
        }
    }
    
  5. In the SlideToggle folder, create a USS file named SlideToggle.uss.

  6. SlideToggle.uss をテキストエディターで開き、そのコンテンツを以下のように置き換えます。`

    .slide-toggle__input {
        background-color: var(--unity-colors-slider_groove-background);
        max-width: 25px;
        border-top-left-radius: 8px;
        border-bottom-left-radius: 8px;
        border-top-right-radius: 8px;
        border-bottom-right-radius: 8px;
        overflow: visible;
        border-left-width: 1px;
        border-right-width: 1px;
        border-top-width: 1px;
        border-bottom-width: 1px;
        border-right-color: var(--unity-colors-slider_thumb-border);
        border-top-color: var(--unity-colors-slider_thumb-border);
        border-bottom-color: var(--unity-colors-slider_thumb-border);
        max-height: 16px;
        margin-top: 10px;
        border-left-color: var(--unity-colors-slider_thumb-border);
        transition-property: background-color;
        transition-duration: 0.5s;
    }
    
    .slide-toggle__input-knob {
        height: 16px;
        width: 16px;
        background-color: var(--unity-colors-slider_thumb-background);
        position: absolute;
        border-top-left-radius: 25px;
        border-bottom-left-radius: 25px;
        border-top-right-radius: 25px;
        border-bottom-right-radius: 25px;
        top: -1px;
        transition-property: translate, background-color;
        transition-duration: 0.5s, 0.5s;
        translate: -1px 0;
        border-left-width: 1px;
        border-right-width: 1px;
        border-top-width: 1px;
        border-bottom-width: 1px;
        border-left-color: var(--unity-colors-slider_thumb-border);
        border-right-color: var(--unity-colors-slider_thumb-border);
        border-top-color: var(--unity-colors-slider_thumb-border);
        border-bottom-color: var(--unity-colors-slider_thumb-border);
    }
    
    .slide-toggle__input--checked {
        background-color: rgb(0, 156, 10);
    }
    
    .slide-toggle__input--checked > .slide-toggle__input-knob {
        translate: 8px 0;
    }
    
    .slide-toggle:focus .slide-toggle__input-knob {
        border-left-width: 1px;
        border-right-width: 1px;
        border-top-width: 1px;
        border-bottom-width: 1px;
        border-left-color: var(--unity-colors-input_field-border-focus);
        border-right-color: var(--unity-colors-input_field-border-focus);
        border-top-color: var(--unity-colors-input_field-border-focus);
        border-bottom-color: var(--unity-colors-input_field-border-focus);
    }
    

UI Builder を使って UXML ファイルへスライドトグルを追加する

  1. In the SlideToggle folder, create a UI Document file named SlideToggleUsage.uxml.
  2. UI Builder で SlideToggleUsage.uxml を開きます。
  3. UI Builder で、Library > Project > MyUILibrary を選択します。
  4. SlideToggleHierarchy ウィンドウにドラッグします。
  5. Inspector で、Label にトグルのラベルテキストを入力します。
  6. StyleSheets セクションに、既存の USS として SlideToggle.uss を加えます。
  7. UI Builder を保存して終了します。

スライドトグルのテスト

  1. サンプルシーンで、UI Document ゲームオブジェクトを作成します。
  2. UI Document を選択し、SlideToggleUsage.uxmlInspectorSource Asset フィールドにドラッグします。
  3. 再生モードにします。トグルをクリックする、Enter キーを押す、Return キーを押す、または、Space キーを押す動作を行うと、トグルを前後に切り替えることができます。

その他の参考資料

カスタムコントロール
Create a radial progress indicator