Unity 6.3
0 онлайн 86 гостей 3 в системе
Вход
UI Toolkit для продвинутых разработчиков Глава 12 из 14 Оригинал, стр. 120

Пользовательские элементы управления

Пользовательские элементы управления

UI Toolkit предоставляет стандартный набор элементов для построения интерфейсов, но вы также можете создавать пользовательские элементы управления под задачи своего приложения. Например, индикатор здоровья может менять цвет в зависимости от текущего значения: по мере его снижения плавно переходить от зелёного к жёлтому и красному. Такой элемент можно без дополнительной настройки использовать для разных персонажей или приспособить для других показателей, например маны или силы. Этот самодостаточный элемент управления станет более наглядной заменой стандартному ползунку из библиотеки UI Toolkit. Пользовательские элементы управления позволяют заключить функциональность в самостоятельные компоненты и повторно использовать их в разных частях интерфейса. Хорошо спроектированный элемент не зависит от конкретного контекста, самодостаточен и способствует повторному использованию кода, упрощая сопровождение проекта. Не стоит создавать пользовательский элемент управления для части интерфейса, которая жёстко связана с конкретным компонентом и не имеет самостоятельной функции, например для игрового меню целиком.

Атрибут UxmlElement Чтобы создать пользовательский элемент управления, определите новый C#-скрипт, класс которого наследуется от VisualElement или от более подходящего производного класса. Нужен элемент, похожий на кнопку? Унаследуйте его от Button.

производительности |

Чтобы пользовательский элемент управления стал доступен в UXML и UI Builder, добавьте к его классу атрибут UxmlElement. Сам класс должен быть объявлен как public partial:

[UxmlElement] public partial class ExampleElement: VisualElement {

} После этого пользовательский элемент управления появится в разделе Library UI Builder, в категории Custom Controls (C#). Оттуда его можно перетащить в окно Hierarchy.

Пользовательские элементы управления отображаются в библиотеке UI Builder.

производительности |

Визуальные элементы не являются GameObject, поэтому у них нет привычных событий жизненного цикла Awake, OnEnable, OnDisable и OnDestroy. Пользовательский элемент управления инициализируется в конструкторе.

[UxmlElement] public partial class ExampleElement: VisualElement {

C#
// Constructor

public ExampleElement() { // Initialization }

}

Инициализацию также можно отложить до добавления пользовательского элемента в интерфейс. Для этого зарегистрируйте обратный вызов AttachToPanelEvent. Чтобы определить, когда элемент удалён из интерфейса, используйте обратный вызов DetachFromPanelEvent.

Атрибут UxmlAttribute Если добавить к свойству атрибут UxmlAttribute, оно появится в окне Inspector UI Builder и начальное значение можно будет задать интерактивно. Это особенно удобно при совместной работе с дизайнером: изменения в Inspector не требуют правки кода. Примените UxmlAttribute к каждому свойству, которое требуется открыть для настройки. Имя атрибута можно изменить аргументом name. При выборе элемента управления в Hierarchy его пользовательские атрибуты отображаются в Inspector, где их можно настроить напрямую. Атрибуты-декораторы изменяют представление полей пользовательских атрибутов примерно так же, как при работе с MonoBehaviour. Среди полезных декораторов TextArea, Tooltip, Range, Header, Min, Multiline, Space и Delayed. Например, Range добавляет ползунок для выбора значения в заданном диапазоне.

производительности |

Пользовательские атрибуты отображаются в Inspector UI Builder.

Ниже приведён простой пример пользовательского элемента управления с атрибутом UxmlElement и двумя открытыми свойствами, отмеченными UxmlAttribute.

[UxmlElement] public partial class ExampleElement: VisualElement { [UxmlAttribute(name:"my-text")]

C#
public string myStringValue { get; set; }
[UxmlAttribute] public int myIntValue { get; set; }
}

В этом примере благодаря параметру name свойство MyStringValue отображается в Inspector под именем "My Text". Свойства MyStringValue и MyIntValue можно редактировать в Inspector, когда в Hierarchy выбран экземпляр ExampleElement.

производительности |

До Unity 6 для создания пользовательских элементов управления требовалось реализовывать классы UxmlTraits и UxmlFactory, которые отвечали за регистрацию атрибутов и создание экземпляров пользовательских элементов. В Unity 6 появились атрибуты UxmlElement и UxmlAttribute, упрощающие этот процесс. Они напрямую делают пользовательские элементы управления и их свойства доступными в UXML и UI Builder. Новый рабочий процесс требует меньше шаблонного кода и ускоряет настройку элементов интерфейса.

Пример: пользовательский переключатель-ползунок Простой пример пользовательского элемента управления переключатель-ползунок, представляющий логическое значение. Он может быть привлекательнее стандартного переключателя. Дополнительная визуальная обратная связь - анимация ползунка, смена цвета и динамический текст - делает интерфейс понятнее.

Пользовательский переключатель-ползунок представляет логическое значение.

Определение пользовательского элемента управления Простая реализация такого элемента находится в сцене CustomControlsDemo проекта QuizU. Чтобы разобраться в её работе, откройте скрипт SlideToggle.cs; его фрагменты приведены ниже. Пользовательский элемент SlideToggle наследуется от наиболее подходящего базового класса - в данном случае BaseField<bool>. Атрибут UxmlElement делает элемент доступным в UXML и UI Builder, благодаря чему его можно использовать повторно.

[UxmlElement] public partial class SlideToggle : BaseField<bool> {

C#
// …

производительности |

C#
public string EnabledText { get; set; }
= "Enabled";
[UxmlAttribute] public string DisabledText { get; set; }
= "Disabled";
[UxmlAttribute] public Color EnabledBackgroundColor { get; set; }
= new Color(0f, 0.5f, 0.85f,1f);
[UxmlAttribute] public Color DisabledBackgroundColor { get; set; }
= Color.gray;
Визуальная структура состоит из фона (m_Input) и ползунка (m_Knob), а внешний вид задаётся классами USS.
C#
public SlideToggle(string label) : base(label, new VisualElement()) {
    AddToClassList(ussClassName);
    m_Input = this.Q(className: BaseField<bool>.inputUssClassName);
    m_Input.AddToClassList(inputUssClassName);
    m_Input.name = "input";
    m_Knob = new();
    m_Knob.AddToClassList(inputKnobUssClassName);
    m_Knob.name = "knob";
    m_Input.Add(m_Knob);
    labelElement.name = "label";
    labelElement.text = (value) ? "enabled" : "disabled";
    Обработчики реагируют на щелчки, нажатия клавиш и события навигации, поэтому состояние элемента можно менять несколькими способами.

производительности |

C#
// … RegisterCallback<ClickEvent>(evt => OnClick(evt));

RegisterCallback<KeyDownEvent>(evt => OnKeydownEvent(evt));
// …

}
static void OnClick(ClickEvent evt) {
    var slideToggle = evt.currentTarget as SlideToggle;
    slideToggle.ToggleValue();
    evt.StopPropagation();
}
static void OnKeydownEvent(KeyDownEvent evt) {
    var slideToggle = evt.currentTarget as SlideToggle;
    if (slideToggle.panel?.contextType == ContextType.Player) return;
    if (evt.keyCode == KeyCode.KeypadEnter || evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.Space) {
        slideToggle.ToggleValue();
        evt.StopPropagation();
    }
}

При переключении элемента надпись и цвет фона автоматически обновляются, обеспечивая визуальную обратную связь. Здесь SetValueWithoutNotify обновляет визуальное состояние переключателя, не вызывая ChangeEvent. Этот метод вызывается внутри элемента при изменении значения, поэтому интерфейс обновляется корректно и не попадает в бесконечный цикл обновлений.

C#
public override void SetValueWithoutNotify(bool newValue) {
    base.SetValueWithoutNotify(newValue);
    m_Input.EnableInClassList(inputCheckedUssClassName, newValue);
    m_Input.style.backgroundColor = newValue ? EnabledBackgroundColor : DisabledBackgroundColor;
    labelElement.text = (value) ? EnabledText : DisabledText;
}

производительности |

Изучите пример реализации в сцене CustomControlsDemo. Чтобы переключить активное состояние элемента, щёлкните по нему мышью или нажмите Enter либо пробел. В этом примере при переключении динамически меняются надпись и цвет фона, а короткая анимация обеспечивает визуальную обратную связь.

В Inspector задайте надписи и цвета фона для включённого и выключенного состояний.

Настройте текст и цвета SlideToggle.

Использование SlideToggle После компиляции SlideToggle можно встраивать в любую часть интерфейса. Используйте пользовательский класс SlideToggle так же, как любой другой визуальный элемент. Ниже приведён пример, в котором SlideToggle включает и отключает звук:

C#
public class MuteAudioToggle : MonoBehaviour {
    [SerializeField] AudioSettingsSO m_AudioSettingsSO;
    [SerializeField] UIDocument m_Document;
    void OnEnable() {
        var root = m_Document.rootVisualElement;
        SlideToggle slideToggle = root.Q<SlideToggle>("master-audio-toggle");

производительности |

C#
if (slideToggle != null) {
    slideToggle.value = !m_AudioSettingsSO.IsMasterMuted;
    slideToggle.RegisterValueChangedCallback(evt => m_AudioSettingsSO.IsMasterMuted = !evt.newValue);
}
}
}

Здесь SlideToggle входит в существующий UXML-документ. MonoBehaviour находит его по имени в визуальном дереве, а затем методом RegisterValueChangedCallback связывает состояние переключателя с настройками звука.

Поскольку SlideToggle - самостоятельный пользовательский элемент, его можно применять для любых переключателей в интерфейсе. Например, в проекте UI Toolkit Sample - Dragon Crashers похожий SlideToggle включает и отключает счётчик кадров в секунду.

Стилизованный переключатель из проекта UI Toolkit Sample - Dragon Crashers

Адаптируйте SlideToggle к требованиям приложения: он отлично подходит для настроек графики, звука и игрового процесса. Создайте его один раз и используйте везде, где нестандартный переключатель улучшит взаимодействие с пользователем. Полную реализацию см. в скрипте SlideToggle.cs проекта QuizU.

производительности |

Создание других пользовательских элементов управления Если нужного элемента нет в стандартной библиотеке UI Toolkit, его можно создать самостоятельно. Вот несколько примеров применения пользовательских элементов управления в играх:

- Индикаторы здоровья и прогресса. Такие игровые показатели, как здоровье, мана и сила, сильно зависят от игрового процесса, поэтому хорошо подходят для пользовательских элементов управления. Откройте через UxmlAttribute максимальное и текущее значения, а также цвета состояний, чтобы можно было настраивать цветовые градиенты. - Рейтинговые звёзды. Этот элемент работает как сегментированный индикатор прогресса и представляет целое значение, например количество звёзд за прохождение уровня. Создайте визуальный элемент с несколькими дочерними элементами, которые переключаются между заполненным и пустым состояниями. Откройте в Inspector целочисленное значение и его максимум, а изображения спрайтов позвольте настраивать через UxmlAttribute. - Представление с вкладками. Вкладки часто используются для переключения между представлениями или разделами одного окна. Создайте пользовательский элемент со строкой вкладок и областью содержимого. Каждая вкладка может быть визуальным элементом, похожим на кнопку; предусмотрите возможность динамически добавлять и удалять вкладки. Не забывайте, что в большинстве случаев визуальный эффект можно усилить анимированными переходами USS. Пользовательские элементы управления позволяют игрокам использовать жесты, щёлкать, прокручивать и переключать элементы уникального интерфейса вашей игры. Нам не терпится увидеть, что вы создадите.