# UI Navigation (不使用滑鼠來選擇 UI)
在 Unity 中,如果要使用上下左右 (i.e. 鍵盤、搖桿、D-pad)控制 UI,就必須要先設定 UI Navigation。
## 手動啟用
先找到場景上的 Event System,設定好 First Select,也就是開啟場景時**第一個被選擇**的 UI 物件
(雖然這個欄位可以放所有 GameObject,但如果該 GameObject 不可以被選擇,視同沒有效果)

同時,Unity 預設的顏色都很白、不容易被察覺。這裡我們把「被選中」顏色設的明顯一點 (<span style="color:#39C5BB">#39C5BB</span>)。

使用 Navigation 設定該物件可以透過上下、左右或是我全都要來選中;
點選 Visulaization 可以看到 UI 互動的流程圖。

## 自動化腳本
如果懶得設定上面那些東西,我寫了個小腳本可以動態變更場景上的可選擇物件,取名叫 `UiNavigationTweak` 然後拉進場景裡就可以了。
```csharp=
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
public class UiNavigationTweak : MonoBehaviour
{
void Start()
{
Refresh();
}
public void Refresh()
{
var selectables = Transform.FindObjectsOfType<Selectable>();
var eventSystem = GameObject.FindObjectOfType<EventSystem>();
Color32 mikuColor = new Color32(0x39, 0xc5, 0xbb, 0xff);
int i = 0;
// mod all selected color
foreach(var selectable in selectables)
{
var c = selectable.colors;
c.selectedColor = mikuColor;
selectable.colors = c;
i++;
}
// evs
if(i > 0 && eventSystem)
{
eventSystem.SetSelectedGameObject(selectables[0].gameObject);
Debug.Log($"[UiNavigationTweak] Modded {i} objects.");
}
}
}
```
:::info
:::spoiler 如果專案會動態改變 UI,可以利用定期偵測這些變更把它套用
也可以由外部腳本呼叫 `Refresh()`
```csharp=
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
public class UiNavigationTweak : MonoBehaviour
{
/// <summary>
/// Start is called on the frame when a script is enabled just before
/// any of the Update methods is called the first time.
/// </summary>
IEnumerator Start()
{
while(true)
{
Refresh();
yield return new WaitForSeconds(1);
}
}
/// <summary>
/// Start is called on the frame when a script is enabled just before
/// any of the Update methods is called the first time.
/// </summary>
public void Refresh()
{
var selectables = Transform.FindObjectsOfType<Selectable>();
var eventSystem = GameObject.FindObjectOfType<EventSystem>();
Color32 mikuColor = new Color32(0x39, 0xc5, 0xbb, 0xff);
int i = 0;
// mod all selected color
foreach(var selectable in selectables)
{
var c = selectable.colors;
c.selectedColor = mikuColor;
selectable.colors = c;
i++;
}
// evs
if(i > 0 && eventSystem)
{
Debug.Log($"[UiNavigationTweak] Modded {i} objects.");
if(!eventSystem?.currentSelectedGameObject?.activeInHierarchy ?? true)
eventSystem.SetSelectedGameObject(selectables[0].gameObject);
}
}
}
```
:::