Unity 6.3
0 онлайн 111 гостей 3 в системе
Вход
UI системы Шаг 173 из 317

Система фокусировки в UI Toolkit

Система фокуса в UI Toolkit управляет тем, какой элемент в данный момент получает ввод с клавиатуры или навигации. Она контролирует, как фокус перемещается между элементами, и вызывает события фокуса, когда элементы получают или теряют фокус.

Ключевые концепции

Система фокуса состоит из нескольких ключевых компонентов:

  • focusable: Может ли этот элемент получить фокус?
  • canGrabFocus: Может ли данный элемент быть в настоящее время фокусирован (видим, включён и т.д.)?
  • tabIndex: Порядок, в котором элементы фокусируются при навигации.
  • delegatesFocus: Если true, фокус переносится на подходящий дочерний элемент.
  • Focus(): Метод запроса фокуса на элементе.
  • Blur(): Метод удаления фокуса с элемента.
  • FocusController: управляет состоянием фокуса и навигацией для панели.
  • IFocusRing: Интерфейс для логики навигации фокуса.
  • FocusChangeDirection: Описывает направление навигации, например Следующий, Предыдущий, Вверх и Вниз.

Рабочий процесс Focus

Система фокусировки работает следующим образом:

  1. Ввод пользователя может вызвать изменение фокуса двумя способами: напрямую, через взаимодействие указателя (например, щелчок мыши или прикосновение), или косвенно, через события навигации (например, Tab, Shift+Tab или клавиши со стрелками), которые затем приводят к событиям фокуса.
  2. EventDispatcher обрабатывает ввод и, когда это необходимо, просит FocusController изменить фокус.
  3. FocusController консультируется с IFocusRing для определения следующего фокусируемого элемента.
  4. Объект FocusController создаёт события изменения фокуса (например, FocusEvent и BlurEvent) и добавляет их в очередь событий объекта EventDispatcher. Объект EventDispatcher отправляет эти события после завершения обработки текущего пользовательского ввода.
  5. После того, как EventDispatcher отправляет события фокуса, вновь фокусируемый элемент получает фокус. Каждый элемент вдоль пути распространения событий может обрабатывать эти события с помощью обратных вызовов событий в коде.
  6. Если элемент имеет delegatesFocus = true, то фокус автоматически передается дочернему элементу, который может быть фокусирован.

На следующей диаграмме показаны компоненты системы фокусировки и их взаимодействие:

Диаграмма системы фокусировки
Диаграмма системы фокусировки

Порядок фокусировки элементов

Каждая панель имеет кольцо фокуса, которое определяет порядок фокуса элементов. По умолчанию, поиск по глубине (DFS) в визуальном дереве определяет порядок фокуса элементов. Например, порядок фокуса для дерева, изображенного на следующем изображении, является F, B, A, D, C, E, G, I, H.

Порядок фокусировки
Порядок фокусировки

Некоторые события используют порядок фокуса для определения того, на каком элементе находится фокус. Например, объектом события клавиатуры является элемент, на котором находится фокус.

Свойства tabIndex можно использовать для настройки порядка фокуса следующим образом:

  • Если tabIndex равен нулю, элемент сохраняет свой порядок табуляции по умолчанию, который определяется алгоритмом кольца фокуса.
  • Если tabIndex является положительным, элемент помещается перед другими элементами, которые либо имеют нулевое значение tabIndex (tabIndex = 0), либо значение tabIndex меньше его собственного.
  • Если tabIndex является отрицательным, элемент удаляется из навигации по вкладкам.

Изменение фокуса

События фокуса происходят, когда элемент получает или теряет фокус. Вы можете использовать метод element.Focus() для изменения фокуса. Этот метод отправляет FocusEvent, который обрабатывается в очереди событий. Фактическое изменение фокуса вступает в силу после завершения выполнения текущего обратного вызова события.

Следующий пример устанавливает фокус на кнопку и отслеживает события фокуса:

using UnityEngine;
using UnityEngine.UIElements;

[RequireComponent(typeof(UIDocument))]
public class FocusExample : MonoBehaviour
{
    void OnEnable()
    {
        var startGameButton = GetComponent<UIDocument>().rootVisualElement.Q<Button>("StartGame");

        startGameButton.RegisterCallback<FocusInEvent>(ev =>
        {
            Debug.Log("FocusInEvent: button is focused and can be activated with keyboard or gamepad input.");
        });

        Debug.Log("Calling startGameButton.Focus().");
        startGameButton.Focus();

        var isFocused = startGameButton.focusController.focusedElement == startGameButton;
        Debug.Log("Immediately after startGameButton.Focus(): isFocused=" + isFocused);

        // Expected output:
        // > Calling startGameButton.Focus().
        // > FocusInEvent: button is focused and can be activated with keyboard or gamepad input.
        // > Immediately after startGameButton.Focus(): isFocused=true
    }
}

Дополнительные ресурсы