執筆バージョン: Unreal Engine 4.20
|
こんにちは。アシスタントエンジニアの小倉です。
今回は、UE4.20で新たに追加されたListViewウィジェットを紹介します。
目次
ListViewウィジェットとは
ListViewウィジェットの使い方
パフォーマンス検証
ListViewウィジェットとは
ListViewウィジェットは、UE4.20でUMGに新たに公開されたウィジェットの一つです。
ScrollBoxとよく似ており、主に次のような機能を持ちます。
○ 複数の子ウィジェットを追加できる
○ 子ウィジェットが表示領域を超えとき、スクロールで表示位置をスライドできる
ListViewがScrollBoxと異なる点は、追加できる子ウィジェットのクラスを1つしか指定できない代わりに、表示領域内の子ウィジェットを使い回すような挙動(例えば、下へのスクロールによって表示領域の上部を越えて見えなくなったウィジェットは、すぐスクロール先である表示領域下部に移動し、移動先に合わせて表示項目を更新します)をすることです。これにより、ListViewに追加される子ウィジェットは表示に必要な数だけとなり、結果として多量の子ウィジェットを追加するときのヒッチの軽減や、表示中の処理負荷の削減が期待できます。
子ウィジェットを使い回すイメージは次のようになります。

ListViewウィジェットの使い方
EntryItemクラスの作成
ListViewで表示したい項目の情報を保持するオブジェクトのクラスを作成します。
このオブジェクトはUObjectで保持するので、Actorのようなクラスも指定できます。しかし、情報を保持するだけのクラスには多機能すぎるため、ここではUObjectを継承した次のような「BP_EntryItem」クラスを作成しました。このクラスはListViewの項目として表示するテキストを保持する変数を1つだけ持ちます。この変数はConstructObjectノードで値を設定できるように、Expose on Spawnにチェックを入れます。

EntryWidgetクラスの作成
ListViewの項目となるウィジェットブループリントを作成します。
ここではアセットの名前を「WB_Entry」としました。作成したWB_Entryを開き、TextBlockウィジェットを配置します。

次に、Graphタブを開き、ToolBarパネルのClass Settingsを選択します。そして、DetailsパネルにあるInterfacesのAddボタンをクリックし、UserObjectListEntryインターフェースを追加します。

追加した後、インターフェースのイベントであるEventOnListItemObjectSetを実装します。
このイベントは、ListViewのスクロールによって使い回されるウィジェットの内容を更新するときに呼び出されるイベントです。更新する項目の情報を保持するオブジェクトが引数として与えられるので、そのオブジェクトに基づいてウィジェットの内容を更新する処理を実装します。
引数のオブジェクトはListViewに追加するオブジェクトなので、ここではBP_EntryItemオブジェクトになります。BP_EntryItemオブジェクトにキャストして保持するText変数でTextBlockの内容を更新します。

ListViewウィジェットの作成
ListViewウィジェットを表示するためのウィジェットブループリントを作成します。
ここではアセットの名前を「WB_ListView」としました。作成したWB_ListViewを開き、PaletteのListsグループからListViewを次のように配置します。

この状態ではListViewの中に「No EntryWidgetClass specified on this list」と表示されてコンパイルエラーとなってしまいます。
そこで、先ほど作成したWB_Entryウィジェットを、次のようにEntryWidgetClassに指定します。

これでListViewの設定は終了ですが、ListViewは動的にのみ項目を追加できます。
ここでは、ListViewの項目であるBP_EntryItemオブジェクトをListViewに100個追加する処理を作りました。Construct ObjectノードでBP_EntryItemオブジェクトを作成し、それをListViewに追加する処理をForloopで100回行っています。

WB_ListViewをViewportに追加して実行すると、次のようになります。

パフォーマンス検証
ListViewは表示領域中のウィジェットを使いまわしていますが、見た目はほとんどScrollBoxと同じで違いがわかりません。
そこで、多量のウィジェットを扱ったときの処理負荷を計測して、ListViewとScrollBoxのパフォーマンスの違いを検証します。
ウィジェット追加時の処理負荷
ここでは、ListViewとScrollBoxに項目を10000個生成・追加した瞬間の処理負荷を比較しました。
ScrollBoxにBP_Entryを追加する処理を次のようにしました。

表示するテキストによって違いが出ないように、BP_ListViewも変更しました。

これを実行した瞬間の処理負荷はそれぞれ次のようになりました。

ScrollBoxでは明らかなヒッチが起きていることが確認できます。
ListViewはウィジェットを追加しているのではなく、項目の情報を保持するオブジェクトを生成・追加しているだけに対し、ScrollBoxは比較的重いウィジェットの生成・追加処理を10000回も行っているため、このような結果になったと考えられます。
しかし、このような生成・追加時ヒッチは、処理を複数フレームに分散することである程度対処できます。
表示中の処理負荷
ここでは、先ほどと同様にBP_Entryを10000個追加した状態での処理負荷を計測しました。

ListViewには、特に大きな処理負荷がかかっていないのに対し、ScrollBoxはGameスレッドが明らかにボトルネックになっています。
特別な最適化をしていない状態の比較では、ListViewのパフォーマンスの方が優れていることを確認できました。
おわりに
いかがでしたでしょうか。
UE4.20には、ListView以外にもTile View、Tree View、DynamicEntryBoxなどのウィジェットが追加されました。
これらのウィジェットも、また機会があれば紹介したいと思います。
この記事は次のバージョンで作成されました。
Unreal Editor Version: 4.20.3-4369336+++UE4+Release-4.20