キー操作でUIのナビゲーションをループさせる

概要

ボタン

キーの上下でカーソル移動させる際、上図のようにボタンが並んでいるときに最上部から最下部にループしたいケースがあります。
UIコンポーネントには下図のようにナビゲーションの設定項目があるのですが、これらを設定しても自動でループの表現はできません。
Navigation項目をExplicitに設定して各遷移先を明示的に指定すれば可能ですが、手間なので自動で設定するようにします。

ナビゲーション設定

ナビゲーションを自動設定

ヒエラルキー

レイアウトグループを使うことを考えると、ヒエラルキーの順番とボタンの順番は一致しているので、この順番どおりにナビゲーションを設定します。
以下のようなコードを書いて、ボタンの親のオブジェクトにつけます(上図でいうCanvas)。
ボタンなどはSelectableクラスを継承しているのでこれを取得して、全てにナビゲーションモードをExplicitにして遷移先を設定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LoopMenu : MonoBehaviour {
void Start() {
//子のボタンやスライダーなど操作可能なコンポーネントを取得する
var selects = GetComponentsInChildren<Selectable>();
for (var i = 0; i < selects.Length; i++) {
var nav = selects[i].navigation;
nav.mode = Navigation.Mode.Explicit;
nav.selectOnUp = selects[i == 0 ? selects.Length - 1 : i - 1];
nav.selectOnDown = selects[(i + 1) % selects.Length];
selects[i].navigation = nav;
}
}
}

他のケース

例えば、interactableでないボタンは除外する場合は、子のselectableを取得したあとに、以下のようにFilterすれば良いと思います。

selects = selects.Where((s) => s.interactable).ToArray();

また、あまりないと思いますが、ヒエラルキーの順番と一致しない場合はpositionでソートするという方法も考えられます。

使用バージョン

Unity 2019.4.5

Unityカテゴリの記事
Color SpaceがLinearのときUIの透明度が正しくならない
History Inspectorの紹介
敵AIとビジュアルスクリプティング
Chronosを使った感想
Smart Inspectorの紹介
コンポーネントの順番をスクリプトから並び替える
Kris' Favorite Assets が便利
TextMeshProのSprite Assetを更新する
UnityPhysicsDebugDraw2D が便利
色管理を考える
細かいTips
ビルドスクリプトを書く
AnimatorのCulling Modeでハマった話
Vectrosityを使ってUGUI上で線や円のアニメーションをする
スプレッドシートからjsonデータを読み込む
ビジュアルノベルアセットFungusにコマンドを追加してカスタマイズする
Skinned Mesh Renderer の Boundsについて
シーンごとにビルド結果の容量を出す
シーンビューにクオリティ設定のスライダーを出すエディタ拡張
ビルド結果のFile headersが大きい理由
フリーのビジュアルノベルアセットFungusを使ってRPGのイベントを作る
Move To View を改良する
フリーのビジュアルノベルアセットのFungusが便利
Visual Studio で保存時にフォーマットする
スプレッドシートからデータを読み込む
Easy Save2 で シリアライズされたクラスを保存する
ShaderでSpriteの色相をシフトする
Sprite、Texture の 色相をシフトする
uGUIのButtonをクリック時にハイライトのままになる
uGUIのCanvas Groupを使って透過処理をしたり、操作を制限する
自作のコンフィグ画面に必要なもの
uGUIでトグルなボタンを作る
uGUI で動的にボタンを作る
Easy Save2 を使ってみる
csv読み込んで ローカライズ
LoadLevelAdditive で共通シーンを加算
画面全体に色をかける
Any State でどこからでも遷移できるようにする
iTween のStop ではまる
sprite の multiple で 境界がおかしくなる
Renderer の Materials を スクリプトから設定する
2D画面に線を引く Line Renderer
背景をスクロールさせる