Table of Contents

Ввод, фокус и навигация

IcyUI получает ввод с мыши, клавиатуры, геймпада и сенсорного экрана через интеграцию с движком и направляет его элементу, которому он предназначен: элементу под указателем или элементу в фокусе. В игре, где играют геймпадом, каждым элементом управления можно пользоваться без мыши.

Ввод указателем

Мышь и касания получает самый верхний элемент под указателем: сначала оверлеи (всплывающие окна, диалоги), затем корневые элементы сверху вниз по порядку отрисовки. Элементы с выключенным IsHitTestVisible, скрытые или полностью прозрачные пропускаются, как и всё, что находится за пределами родителя с ClipToBounds.

Сенсорный ввод добавляет жесты, которые распознаются и по касаниям, и по мыши: касание, удержание, перетаскивание и масштабирование двумя пальцами. ConfigureGestures настраивает их: HoldDelay (0,5 с), MultiTapDelay (0,3 с) и Slop (10 px движения, после которых нажатие становится перетаскиванием).

Примечание

Бэкенд DesktopGL в MonoGame не сообщает о сенсорном вводе; мышь при этом работает.

Фокус

Фокус клавиатуры и геймпада в каждый момент у одного элемента: FocusedElement Canvas. Элементы управления, которыми может пользоваться игрок, могут получать фокус (IsFocusable); щелчок или касание переводит на них фокус, а из кода это делает Canvas.Focus(element), например чтобы меню открывалось на первой кнопке.

Клавиатура Геймпад Действие
Стрелки Крестовина Перевести фокус на ближайший элемент в этом направлении.
Tab, Shift+Tab Нажатие правого / левого стика Перевести фокус на следующий / предыдущий элемент.
Enter A Задействовать элемент в фокусе (нажать кнопку, переключить флажок, открыть список).
Escape B Закрыть открытый диалог или список.

Навигация стрелками пространственная: она выбирает ближайший элемент в нажатом направлении на экране, поэтому работает для любой компоновки без заданного порядка. Элемент в фокусе прокручивается в область видимости. Некоторые элементы управления сами используют стрелки, пока они в фокусе (поле ввода двигает курсор ввода, дерево переходит между строками), и отдают их дальше на своих краях.

Примечание

Кнопки X и Y геймпада вызывают события «назад» и «вперёд» (INavigationEvents.NavigateBack и NavigateForward) для вашего собственного кода, но Frame на них пока не реагирует. Добавьте на страницу кнопку «Назад», которая вызывает Frame.Navigation.TryNavigateBack().

Область фокуса (IsFocusScope) удерживает навигацию внутри себя: открытые Window или Dialog — такие области, и после их закрытия фокус возвращается туда, где был. Задайте Canvas.IsKeyboardNavigationEnabled равным false, чтобы выключить навигацию стрелками и Tab, например пока эти клавиши использует игровой процесс.

Перетаскивание

Перенос данных между элементами (предмета из одной ячейки инвентаря в другую) использует два интерфейса. Источник реализует IDragSource и, когда на нём начинается перетаскивание, решает, что он переносит и что следует за указателем; цель реализует IDropTarget и решает, принимает ли она перенос:

/// <summary>An inventory slot: drag its item to another slot.</summary>
public sealed class InventorySlot : Border, IDragSource, IDropTarget
{
    public string? Item { get; set; }

    public bool TryBeginDrag(Point screenPoint, out object? payload, out UIElement? preview)
    {
        payload = Item;
        preview = Item is null ? null : new TextBlock { Text = Item };
        return Item is not null;
    }

    public bool CanDrop(DragDropSession session) => Item is null && session.Payload is string;

    public void OnDragEnter(DragDropSession session) => Opacity = 0.7f;

    public void OnDragOver(DragDropSession session)
    {
    }

    public void OnDragLeave(DragDropSession session) => Opacity = 1f;

    public void OnDrop(DragDropSession session)
    {
        Item = (string)session.Payload;
        ((InventorySlot)session.Source).Item = null;
        Opacity = 1f;
    }
}

Canvas находит источник, поднимаясь вверх от элемента под указателем, двигает изображение вслед за указателем и на каждом шаге спрашивает цель под ним. Перетаскивание, которое лишь двигает что-то внутри одного элемента управления (бегунок ползунка, разделитель SplitPane), встроено в эти элементы управления.

Типичные ошибки

  • Ввод интерфейса и ввод игры. Проверяйте IsMouseOverGUI, прежде чем игра отреагирует на щелчок; см. Canvas, хост и дерево элементов.
  • Нет фокуса — нечем управлять. Меню, открытое для геймпада, должно переводить фокус на свой первый элемент управления.
  • Некоторыми элементами управления пока нельзя пользоваться с клавиатуры: элементами списка, заголовками вкладок и значением ползунка; см. страницу каждого элемента управления.

См. также

  • Кнопки и другие страницы элементов управления — клавиши каждого из них.
  • Диалоги и окна — области фокуса.