スクロール機能のついたリストボックスを作ろうと思って、ブループリントを触り始めたら思いのほか手間取ってしまいました。当たり前のように使ってるUIのしくみって作ってみないと分らないものですね。ちょっとボリュームがあるので、うまくまとまるか自信ないけど書いていきます。
ちなみに
UnityとかiPhone開発界隈ではスクロールビューとか呼ばれているみたいですね。
リストボックスで検索すると、Excelの画像がたくさん出てきます。
今回作ってみたのはこんな感じ。
UMGには ScrollBox というものが用意されていますが、今回は VerticalBox(バーティカルボックス) を使います。
さて、そもそものリストボックスについておさらい。
表示しきれない量の選択肢に対応するための仕組みで、表示範囲が移動するのがポイント。
今回ゲームパッド操作を考えているので、カーソルが存在します。カーソルが移動して表示範囲を越えようとしたときにようやく表示範囲が移動します。表示範囲内であればカーソルが動いても表示範囲は動きません。
つまり、カーソル移動と表示範囲の移動は完全には連動しません。
こんなとこでしょうか。
UMGでこれを再現するために、CanvasPanel で表示範囲を決めて、VerticalBox をその子供にします。VerticalBoxを動かせば、CanvasPanelの外は描画されないので、バッチリです。
リストアイテムを作る
リストとして並べるパーツを作ります。
コンテンツブラウザで Add New ボタンか、右クリックで User Interface > Widget Blueprint を選択。
とりあえず WD_ListItem と命名して編集開始。
シンプルに下敷きの板(Image)とテキストブロック(TextBlock)の2パーツです。
テキストブロックに g が入っているのは、ディセンダ(ベースラインより下の部分。小文字の g j p q y 用)の加減が分かるようにするためです。
さらにサイズを大きめに設定して、下敷きよりも下にハミ出させているのは、VerticalBoxで並べたときにスキマを作るためです。(VerticalBoxの設定でできそうなノードを見つけたのですが、まだできないっぽい)
テキストブロックは、内容を自由に書き変えたいので、変数化します。
Detailsタブの一番上にあるチェックボックスにチェックを付けます。
チェックボックス左のフォームは変数名として使われます。
このリストアイテムは、カーソルの乗った状態(=フォーカス)と、乗ってない状態(=デフォルト)の2つがあります。
これをアニメーションで作ります。
これで見た目は完成。編集モードを Graph に切り替えます。
さっそく関数を2つ用意します。うえの2つのアニメーションを再生するためのものです。関数にしておけば、自分以外のブループリントなどから呼び出してもらうことができます。関数は、My Blueprintタブの Functions にある +ボタンをクリックして追加します。
中身は以下のようにつなぎます。まずは setDefsult 関数。
ほぼ同じ内容で setFocus 関数。
両方とも同じカラーを変更するタイプのアニメーションなので、安全のためにいったん先に動いているであろうアニメーションをストップさせてから、再生するようにしています。
最後にテキストブロックの内容を変える仕組みを用意します。
以前の記事では関数を使っていましたが、今回は使いません。
代わりに変数を一つ用意します。タイプはテキスト型。
Editable と Expose on Spawn にチェックを付けます。
次に Event Graph を編集します。
初めから置いてあった、Event Construct ノードに変数化したテキストブロックをつなぎます。Set Textノードは、テキストブロックのGetノードから 「set」 と 「text」 で検索するとすぐに見つかると思います。
In Textピンにさきほど作った変数を接続。右端にデフォルトアニメーションを再生する関数をつないでおきます。UMGは最後に触った状態から表示を開始する仕様なので、強制的にデフォルト状態にしておけば安心です。
以上でリストアイテム完成です。保存して閉じます。
リストを並べる
作ったリストパーツを並べて表示するための『親』Widgetを作ります。
今度は WD_ListBox と名付けました。
まずはUMGでパネルをレイアウトします。
レイアウトしたのは3つ。
1.下敷き(Image)
2.表示範囲用(CanvasPanel)
3.リスト並べ用(VerticalBox)
3を2の子供にします。
VerticalBoxだけ太字になっているのですが、これは変数化しているという意味を表しています。ブループリントから触るのはVerticalBoxだけです。
追記: 2020/6/27
この記事を書いていた当時、CanvasPanel はデフォルトでクリッピング(キャンバスの外側にはみ出た部分は描画しない)してくれていましたが、最近は設定が変更になったようで、今回のような表示方法では、明示的にクリッピングするよう、設定を変更する必要があります。
CanvasPanel にこの Clip to Bounds を設定すると、子供にしたVerticalBox は CanvasPanelの中だけに描画されます。
<<<
ちょっと名前が長くなるのですが、なるべく何のパーツかわかるようにアンダースコアの前の部分は残すようにしています。
これでUMGのレイアウトは完了です。
編集モードを Graph に切り替えます。
まずリストパーツに表示するアイテム名を作ります。
実際にゲームなどで汎用的に使う場合、他からリストを受け取ることになると思いますが、今回はテスト用に自前で用意します。ブループリントをスッキリさせたいのと、後から取り外しがしやすいので、マクロにします。
My Blueprint > Macros の右端にある+ボタンをクリック。
Detailsタブの下の方にある Outputs のところにテキスト型の配列を追加します。
グラフのノードも変化しているので、ピンからドラッグしてMakeArray ノードを取り出します。
あとは Add pin+ を好きなだけクリックして、テキストを入力していきます。
できたら、このマクロを使ってリストを並べる処理を作ります。
タブを マクロから Event Graph に切り替えたら、作ったばかりのマクロを取り出します。このマクロは白いピンがないので、このままだとつながりません。
そこで ForEachLoop ノードの出番です。これは配列変数と相性抜群で、とても便利なノードです。配列の要素(中身とか引き出しのイメージ)の数に合わせて処理をしてくれます。要素が尽きると Completed ピンに流れます。
さらに便利なのが、ArrayElement ピンです。つないだ配列の要素を順番に取り出してくれるのです。
普通の ForLoop ノードだったらこうなります。
Loop Body は、繰り返し行う処理をつなぐためのピンです。
ここに CreateWidget ノードをつないで 『子』の リストパーツWidget を量産します。
Classの部分に 『子』のWidgetをセットしたとたん、ノードの下部分 に新しくピンが出現します。Expose on Spawn した変数がここに顔を出すので、ForEachLoopのArrayElementピンとつないでやります。
新たに『子』としてCreateWidgetされたパーツは、後から個別にデフォルトとフォーカスを切り替えるので、配列変数にしまい込んでいきます。
まず、Return Valueピンの上で右クリックして、Promote to Variable を選択します。
この操作で 『子』Widget型の変数が作られます。
これを配列変数に切り替えるのですが、このままやると警告が出てちょっとイヤな感じなので、いったんグラフ上で消してしまいます。Variablesリストには残っているのでそこで設定と名前を変更します。
この配列変数を、Addノードを使って CreateWidgetノードとつなぎます。
最後にVerticalBoxに追加します。Variablesリストからドラッグ&ドロップして、Getで配置したら、Add Child to VerticalBox ノードを取り出して、下図のようにつなぎます。
ループ処理が完成しました。
仕上げにカーソルを表現します。
ForEachLoopノードの Completed ピンに 『子』Widgetで用意した setFocus 関数をつなぎます。
この辺りで一度表示を確認してみます。
レベルブループリントを編集します。
再生してみると、
見た目はほぼ完成です。
今回はこの辺までにします。
次回ひき続き動かす部分を作っていきます。
ではでは