UI 개체에서 포커스 유지

페이지 업데이트 :
페이지 생성 날짜 :

검증 환경

윈도우
  • 윈도우 11
유니티 에디터
  • 2020.3.25에프1

이 팁의 전제 조건

이 팁을 설명하기 위한 전제 조건으로 다음 설정이 미리 이루어졌습니다.

이 팁에서 어떤 점이 도움이 되었나요?

원래 이야기는 어딘가에 있었지만 키워드를 검색하여 찾을 수 없었습니다.

포커스 정보

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 버튼이 로 설정되어 있습니다.

어떻게 작동하는지 실행해 보십시오. 먼저 개체를 클릭하여 선택한 다음 빈 영역을 클릭하여 초점을 잃지 않도록 합니다.

선택되지 않도록 설정된 단추를 클릭해도 초점이 이동하지 않도록 할 수도 있습니다.