Утримання фокуса поза об'єктом інтерфейсу користувача

Сторінка оновлюється :
Дата створення сторінки :

Середовище верифікації

Вікна
  • Вікна 11
Редактор Unity
  • 2020.3.25f1

Передумови для цієї поради

Наступні налаштування були зроблені заздалегідь як обов'язкова умова для пояснення цих порад.

Що ви вважаєте корисним у цій пораді?

Оригінальна історія десь була, але я не зміг її знайти, шукаючи ключові слова.

Про Focus

Об'єкти Unity UI, як і будь-яка інша програма, можуть мати фокус, який вказує на те, що вони активні як об'єкти введення. Однак, якщо ви клацнете або торкнетеся чогось іншого, крім об'єкта, об'єкт із фокусом зникне. Можливо, не вдасться прийняти операції за допомогою клавіатури або геймпада.

У цьому розділі описано, як використовувати скрипти для керування фокусом, щоб він не втрачав фокус у псевдо. Зауважте, що ця підтримка не є функцією 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 встановлено значення .

Спробуйте запустити його, щоб побачити, як він працює. Спочатку клацніть по об'єкту, щоб виділити його, а потім клацніть по порожній області, щоб він не втратив фокус.

Також можна переконатися, що натискання кнопки, для якої встановлено невибір, не переміщує фокус.