Удержание фокуса вне объекта пользовательского интерфейса

Страница обновлена :
Дата создания страницы :

Проверочная среда

Виндоус
  • Windows 11
Редактор Unity
  • 2020.3.25ф1

Необходимые условия для получения этого совета

Следующие настройки были сделаны заранее в качестве предварительного условия для объяснения этих советов.

Что вам помогло в этом совете?

Оригинальная история где-то была, но я не мог найти ее по ключевым словам.

О компании Focus

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

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

Размещение объектов

Тип объекта не имеет значения в управлении фокусировкой, поэтому разместите его соответствующим образом.

Он окрашен так, чтобы было легко видно, что он находится в фокусе.

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

Управляйте, чтобы не терять концентрацию

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

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

using System.Collections;
using System.Linq;                 // 追加
using UnityEngine;
using UnityEngine.EventSystems;    // 追加
using UnityEngine.UI;              // 追加

public class FocusRequired : MonoBehaviour
{
  /// <summary>
  /// <see cref="Selectable"/> をフックするクラスです。
  /// </summary>
  private class SelectionHooker : MonoBehaviour, IDeselectHandler
  {
    /// <summary>親コンポーネント。</summary>
    public FocusRequired Restrictor;

    /// <summary>
    /// 選択解除時にそれまで選択されていたオブジェクトを覚えておく。
    /// </summary>
    /// <param name="eventData"></param>
    public void OnDeselect(BaseEventData eventData)
    {
      Restrictor.PreviousSelection = eventData.selectedObject;
    }
  }

  /// <summary>選択させないオブジェクト一覧。</summary>
  [SerializeField] private GameObject[] NotSelectables;

  /// <summary>直前まで選択されていたオブジェクト。</summary>
  private GameObject PreviousSelection = null;

  /// <summary>
  /// 選択対象のオブジェクト一覧。
  /// </summary>
  private GameObject[] _selectables;

  private void Awake()
  {
    // すべての Selectable を取得する
    var selectableList = (FindObjectsOfType(typeof(Selectable)) as Selectable[]).ToList();

    // 選択除外がある場合は外す
    if (NotSelectables != null)
    {
      foreach (var item in NotSelectables)
      {
        var sel = item?.GetComponent<Selectable>();
        if (sel != null) selectableList.Remove(sel);
      }
    }

    _selectables = selectableList.Select(x => x.gameObject).ToArray();

    // フォーカス許可オブジェクトに SelectionHooker をアタッチ
    foreach (var selectable in this._selectables)
    {
      var hooker = selectable.AddComponent<SelectionHooker>();
      hooker.Restrictor = this;
    }

    // フォーカス制御用コルーチンをスタート
    StartCoroutine(RestrictSelection());
  }

  /// <summary>
  /// フォーカス制御処理。
  /// </summary>
  /// <returns></returns>
  private IEnumerator RestrictSelection()
  {
    while (true)
    {
      // 別なオブジェクトを選択するまで待機
      yield return new WaitUntil(
          () => (EventSystem.current != null) && (EventSystem.current.currentSelectedGameObject != PreviousSelection));

      // まだオブジェクトを未選択、または許可リストを選択しているなら何もしない
      if ((PreviousSelection == null) || _selectables.Contains(EventSystem.current.currentSelectedGameObject))
      {
        continue;
      }

      // 選択しているものがなくなった、または許可していない Selectable を選択した場合は前の選択に戻す
      EventSystem.current.SetSelectedGameObject(PreviousSelection);
    }
  }
}

Я не буду вдаваться в подробности, но Что я делаю, так это сохраняю текущий объект выделения, и если «выбранный объект исчез» или «я выбрал объект, который я не хочу выделять», я возвращаюсь к предыдущему выделению.

Этот компонент может быть присоединен к любому существующему объекту, поэтому EventSystem присоедините его к .

Так как можно указать объект, который вы не хотите выделять в качестве свойства, давайте попробуем разместить кнопку, которую вы не хотите выбирать.

Not Selectables установлена в .

Попробуйте запустить его, чтобы увидеть, как он работает. Сначала нажмите на объект, чтобы выделить его, а затем нажмите на пустую область, чтобы он не потерял фокус.

Кроме того, можно сделать так, чтобы нажатие кнопки, с которой снят флажок, не перемещало фокус.