Mantendo o foco fora do objeto da interface do usuário

Página atualizada :
Data de criação de página :

Ambiente de verificação

Windows
  • Janelas 11
Unity Editor
  • 25.3.2020F1

Pré-requisitos para esta dica

As configurações a seguir foram feitas com antecedência como pré-requisito para a explicação dessas dicas.

O que você achou útil nessa dica?

A história original estava em algum lugar, mas eu não conseguia encontrá-la procurando palavras-chave.

Sobre a Focus

Os objetos da interface do usuário Unity, como qualquer outro aplicativo, podem ter um foco que indica que eles estão ativos como destinos de entrada. No entanto, se você clicar ou tocar em qualquer coisa que não seja o objeto, o objeto com foco desaparecerá. Talvez não seja possível aceitar operações com um teclado ou gamepad.

Esta seção descreve como usar scripts para controlar o foco para que ele não perca o foco em um pseudo. Observe que esse suporte não é um recurso do Unity e pode fazer com que você perca o foco por um momento.

Posicionamento de objetos

O tipo de objeto não importa no controle de foco, então coloque-o adequadamente.

Ele é colorido para que seja fácil ver que está em foco.

Por enquanto, se você executá-lo nesse estado, você pode ver que se você clicar em um lugar vazio depois que o objeto receber o foco, ele perderá o foco.

Controle para não perder o foco

Para fazer isso, crie um script. O nome do script pode ser qualquer coisa, mas FocusRequired deixe-o como .

Digite o código da seguinte maneira:

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

Não vou entrar em muitos detalhes, mas O que estou fazendo é manter o objeto de seleção atual e, se "o objeto selecionado se foi" ou "selecionei um objeto que não quero que seja selecionado", estou revertendo para a seleção anterior.

Esse componente pode ser anexado a qualquer objeto existente, portanto EventSystem , anexe-o ao .

Como é possível especificar o objeto que você não deseja que seja selecionado como uma propriedade, vamos tentar colocar um botão que você não deseja selecionar.

Not Selectables está definido como .

Tente executá-lo para ver como ele funciona. Primeiro, clique em um objeto para selecioná-lo e, em seguida, clique em uma área vazia para que ele não perca o foco.

Você também pode certificar-se de que clicar em um botão definido como desmarcado não move o foco.