こちらの記事の続きになります。ダウンロードもこちら。
導入
ダウンロードした unitypackage をインポート
InputSystem の場合、Padd(PadInput) というライブラリを使用します。
(レガシー Input であれば Padd は必要ありません)
UI/ScrollView を作成する
適当な大きさにしてください。ここでは width: 400、height: 800 の縦スクロールビューとします。
ScrollRect の設定
縦スクロールビューにしたいので、Horizontal のチェックは外し、Horizontal Scrollbar の登録を削除します。
(ヒエラルキーから Scrollbar Horizontal も消してしまいましょう)
ノードを作成する
ここで作成したノードはデモサンプルに入っています。
1マスに表示するための情報(ノード)を作成します。
今回は絵、番号、テキスト、フォーカス下地の4種類にしました。
自分で作る時に気をつけることとして、一番上(親オブジェクト)の Pivot や Anchor は 0.5、0.5 にしておいてください。
(これを守らないとライブラリから警告が出ます。また、表示もズレてしまいます)
他もOKにするのは面倒だった
TableScrollViewer を ScrollView にアタッチする
ScrollRect のあるオブジェクトに、TableScrollViewer をつけます。
また、SourceNode に先ほどの NodeSimple を設定しておいてください。
SourceNode はソースコードから設定することもできます。
ノードを表示するためのコードを作成する
下準備は出来たので、TableScrollViewer を表示するためのコード(Sample.cs)を記述します。
コードは ScrollView か、その一つ上の Canvas にアタッチしてください。
テストコードはこれだけで構いません。
using System.Collections.Generic; using UnityEngine; public class Sample : MonoBehaviour { List<object> viewerList = new List<object>(); void Awake() { TableScrollViewer viewer = this.gameObject.GetComponentInChildren<TableScrollViewer>(); for (int i = 0; i < 16; i++) { viewerList.Add(i * 2); } viewer?.Initialize(); viewer?.SetTable(viewerList.ToArray()); } }
サンプルでは全16 個の viewerList が各ノードに分配されます。
この場合は 0, 2, 4, 6, 8 ... 30 の int 値だけですが、object なので独自のテーブルや ScriptableObject を渡しても構いません。(というより、ほとんどそういう使い方がメインだと思います)
NodeSimple(Node.cs) は、ViewerList と itemIndex を元にノードの表示を決定しています。
Node.cs の次のコードです。
/// <summary> /// 行の表示更新通知があった場合、ここで表示を更新する /// </summary> public override void onEffectChange(int itemIndex) { int no = (int)table[itemIndex]; No.SetText("Line: " + (no+1).ToString("00")); Desc.SetText(Descriptions[no % Descriptions.Length]); Icon.sprite = IconSprites[no % IconSprites.Length]; }
table というのは Sample.cs の viewerList の名前を変えたものです。
itemIndex が、「上から何番目か」を示す数字です。
viewerList は 0, 2, 4, 6, 8 ... という数字が入っていました。それを参照している Line もまた、1, 3, 5, 7 ... と表示されています。(no+1 なので 1 からになっています)
Sample.cs の要素数を 16 から増やしたり、Node.cs で表示物を変更するなどテストしてみてください。
10000 個にしても特に問題なく動くのがわかるかと思います。
文章やアイコンは、サンプルなので Node.cs に直接設定しています。
実際に運用する場合は viewerList に情報を含めた方がいいかと思います。
イベント
Sample.cs を次のように拡張しておいてください。
3つのイベントについて説明します。
using System.Collections.Generic; using UnityEngine; public class Sample : MonoBehaviour { List<object> viewerList = new List<object>(); void Awake() { TableScrollViewer viewer = this.gameObject.GetComponentInChildren<TableScrollViewer>(); for (int i = 0; i < 16; i++) { viewerList.Add(i*2); } viewer?.Initialize(); viewer?.SetTable(viewerList.ToArray()); viewer?.OnSelect.AddListener(OnSelect); viewer?.OnKeyDown.AddListener(OnKeyDown); viewer?.OnCursorMove.AddListener(onCursorMove); } public void onCursorMove(object[] table, int itemIndex, int subIndex, bool userInput) { int row = (int)table[itemIndex]; Debug.Log($"move: {row+1}"); } public void OnSelect(object[] table, int itemIndex, int subIndex, bool isCancel) { int row = (int)table[itemIndex]; Debug.Log($"selected : {row+1}"); } public void OnKeyDown(TableScrollViewer.KeyDownArgs args) { if (Input.GetKeyDown(KeyCode.Return) == true) { args.Flag = TableScrollViewer.eKeyMoveFlag.Select; } else if (Input.GetKeyDown(KeyCode.UpArrow) == true) { args.Flag = TableScrollViewer.eKeyMoveFlag.Up; } else if (Input.GetKeyDown(KeyCode.DownArrow) == true) { args.Flag = TableScrollViewer.eKeyMoveFlag.Down; } } }
レガシー Input を使っている場合、次のように変更してください。
・Padd -> Input
・GetKeyDelay -> GetKeyDown
・ePad -> KeyCode
OnSelect(): 選択された時に通知する
table と itemIndex を組み合わせることで、選択された項目(行)を知ることができます。
また、後述するキャンセル操作を行った場合は isCancel == true を返します。
OnKeyDown(): キーボード入力を可能にする
args.Flag に入力値を指示しておくと、TableScrollViewer はその指示に従って動作します。
このイベントによって、アプリ側で自由にキー操作を制御することができます。
例えば Shift(L1) キーを押しながら ↑ を押すとページスクロール…なんてことも可能でしょう。
eKeyMoveFlag に可能な操作が全て記載されています。
上下左右に加えて決定、キャンセルがあります。
キャンセルを指示した場合、OnSelect() の isCancel は true を返します。
OnCursorMove(): カーソルが移動された時の通知
カーソル音や、選択した項目によって説明メッセージを変える時などに使えます。
userInput は false が「プログラムで強制的にカーソル位置を変えた場合」、true の時は「ユーザーが入力して変わった場合」を示します。
とても地味なパラメータですが、例えばカーソル初期位置を指定する場合はカーソル音を鳴らしたくない…など、かゆい所に手が届くパラメータです。
ノードイベント
Content のノードには TableNodeElement を継承したカスタムクラスをアタッチする必要があります。
サンプルでは Node.cs がそれにあたります。
このクラスは3つのイベントがあり、必要なイベント処理を実装します。
(必須なのは onEffectChange() のみです)
onEffectChange(): ノード表示内容変更通知
高速表示するためにノードを使いまわす関係上、要求に応じて表示内容を変える必要があります。
「ノードを表示するためのコードを作成する」でも説明した通り、table と引数の itemIndex によって表示するための情報を取得し、描画アイテムに伝えます。
/// <summary> /// 行の表示更新通知があった場合、ここで表示を更新する /// </summary> public override void onEffectChange(int itemIndex) { int no = (int)table[itemIndex]; No.SetText("Line: " + (no+1).ToString("00")); Desc.SetText(Descriptions[no % Descriptions.Length]); Icon.sprite = IconSprites[no % IconSprites.Length]; }
onEffectFocus(): ノードの選択・非選択変化時に呼ばれる
focus が true(選択)、false(非選択)時にコールされるイベントです。
コルーチンなどでアニメーション処理を行いたい場合、isAnimation が false であれば即書き換え、true であればコルーチンアニメーションを仕込むようにしてください。
isAnimation は「初期状態の選択にはアニメーションいらない、ユーザーが選択した時だけアニメーションする」などのこだわりがある人向けなので、それを気にしなかったり、サンプルのようにそもそもアニメーションさせない場合は無視して構いません。
onEffectClick(): ノードがクリック(決定)された時に呼ばれる
このイベントは多くの場合、何も書かなくても済んでしまうイベントです。(サンプルでも記述していません)
もし選択された場合にちょっとしたアニメーションをさせたい場合など、このイベントを使ってください。
細かい引数の解説については、次の記事に
細切れになってしまって申し訳ありませんが、以下をご覧ください。