Ввод, фокус и навигация
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, хост и дерево элементов.
- Нет фокуса — нечем управлять. Меню, открытое для геймпада, должно переводить фокус на свой первый элемент управления.
- Некоторыми элементами управления пока нельзя пользоваться с клавиатуры: элементами списка, заголовками вкладок и значением ползунка; см. страницу каждого элемента управления.
См. также
- Кнопки и другие страницы элементов управления — клавиши каждого из них.
- Диалоги и окна — области фокуса.