Mantener el foco fuera del objeto de la interfaz de usuario

Actualización de la página :
Fecha de creación de la página :

Entorno de verificación

Windows
  • Windows 11
Unity Editor
  • 2020.3.25f1

Requisitos previos para esta sugerencia

Los siguientes ajustes se han realizado de antemano como requisito previo para la explicación de estos consejos.

¿Qué te resultó útil en este consejo?

La historia original estaba en alguna parte, pero no pude encontrarla buscando palabras clave.

Acerca de Focus

Los objetos de la interfaz de usuario de Unity, como cualquier otra aplicación, pueden tener un foco que indique que están activos como destinos de entrada. Sin embargo, si hace clic o toca cualquier cosa que no sea el objeto, el objeto con el foco desaparecerá. Es posible que no sea posible aceptar operaciones con un teclado o un gamepad.

En esta sección se describe cómo utilizar las secuencias de comandos para controlar el foco de modo que no pierda el foco en un pseudo. Tenga en cuenta que este soporte no es una característica de Unity y puede hacer que pierda el enfoque por un momento.

Colocación de objetos

El tipo de objeto no importa en el control de enfoque, así que colóquelo adecuadamente.

Está coloreado para que sea fácil ver que está enfocado.

Por el momento, si lo ejecuta en este estado, puede ver que si hace clic en un lugar vacío después de que el objeto reciba el foco, perderá el foco.

Control para no perder la concentración

Para ello, cree un script. El nombre del script puede ser cualquier cosa, pero FocusRequired déjelo como .

Introduzca el código de la siguiente manera:

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);
    }
  }
}

No voy a entrar en demasiados detalles, pero Lo que estoy haciendo es mantener el objeto de selección actual, y si "el objeto seleccionado se ha ido" o "he seleccionado un objeto que no quiero que se seleccione", estoy volviendo a la selección anterior.

Este componente se puede adjuntar a cualquier objeto que exista, así EventSystem que adjúntelo a .

Dado que es posible especificar el objeto que no desea que se seleccione como propiedad, intentemos colocar un botón que no desee seleccionar.

Not Selectables está ajustado en .

Intente ejecutarlo para ver cómo funciona. Primero, haga clic en un objeto para seleccionarlo y luego haga clic en un área vacía para que no pierda el foco.

También puede asegurarse de que al hacer clic en un botón que está configurado para no seleccionar no se mueva el foco.