Keeping the focus out of the UI object

Page update date :
Page creation date :

Verification environment

Windows
  • Windows 11
Unity Editor
  • 2020.3.25f1

Prerequisites for this tip

The following settings have been made in advance as a prerequisite for the explanation of these tips.

What did you find helpful in this tip?

The original story was somewhere, but I couldn't find it by searching for keywords.

About Focus

Unity UI objects, like any other app, can have a focus that indicates that they are active as input targets. However, if you click or touch anything other than the object, the object with focus will disappear. It may not be possible to accept operations with a keyboard or gamepad.

This section describes how to use scripting to control the focus so that it does not lose focus in a pseudo. Note that this support is not a Unity feature and may cause you to lose focus for a moment.

Object Placement

The type of object does not matter in focus control, so place it appropriately.

It is colored so that it is easy to see that it is in focus.

For the time being, if you run it in this state, you can see that if you click on an empty place after the object receives focus, it will lose focus.

Control so that you don't lose focus

To do this, create a script. The script name can be anything, but FocusRequired leave it as .

Enter the code as follows:

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

I won't go into too much detail, but What I'm doing is keeping the current selection object, and if "the selected object is gone" or "I have selected an object that I don't want to be selected", I am reverting to the previous selection.

This component can be attached to any object that exists, so EventSystem attach it to .

Since it is possible to specify the object that you do not want to be selected as a property, let's try placing a button that you do not want to select.

Not Selectables button is set to .

Try running it to see how it works. First, click on an object to select it, and then click on an empty area so that it does not lose focus.

You can also make sure that clicking a button that is set to be unselected does not move the focus.