大量のリストを高速に表示する TableScrollView - がくやうら

こちらの記事について色々と大変だった思い出を書き起こしておこうと思います。
(正直俺得にしかならない記事です…!)

はじめに

ScrollView はとても便利な UI です。

ただ…どうしても…重くなるんですよね…。

解消方法は様々な場所で公開されていましたが、その上辺(図とか)だけをサラッといただきつつ、勉強がてら自分で作ってみようというのが今回の目標でした。

図で書くと簡単そうだが…

図を書くのもちょっとしんどいですね(笑)
標準はこんな感じ。必要な Node を全て描画した上で ScrollView だけ切り出してるイメージです。
そりゃ 10000 個とか描画すれば重くなるはず。

理想なこちらです。ScrollView の近辺だけ表示したい。
とはいえ、例えば SetActive() のオンオフとかだと結局 10000 個の呪いは消えません。
(描画は速くなるかもしれないが、ロード時は物凄く遅いし、メモリも食う)

Node はここにある 7 つだけ、表示エリアが移動した時その 7 つを表示してほしい内容に変えるというアプローチが一番リソースを食いません。
10000 個あろうと、実存するのは 7 つだけで済みますし。
7つのノードを使いまわすため、常時ノード書き換えのオーバーヘッドは発生しますが、そのあたりはきちんとキャッシュ管理しておけば、書き換え対象の数を減らすことも可能です。

高速スクロールした場合は、毎フレーム全部書き換え…なんてことも起こりますが。

さて、ノードは 7 つでいいとして 10000 個の情報はどこに? というのが、TableScrollViewer.SetTable() で渡したテーブル情報です。
実体は数字だったりテキストなどの情報体。プレファブで持つより、断然容量も少なくて済みます。

表示エリアを計算するのが厄介

こういうの得意な人であれば迷いは全然ないのでしょうが、Content と ScrollView と Node の3つがあって、左を 0 とすると N 番目は…。RectTransform も加味すると…。

RectTransform はクセ者

また、実際の ScrollView を動かす値はピクセル数ではなく、0~1 の float 値です。(NormalizedPosition)
今でこそ何も見ずに図解できるくらい理解が進みましたが、直感的にピンと来るまで結構苦労しました。
(しかもこれ、Vertical だと 1~0 で逆転するんですよね…座標系に合わせるとそうなるのは理解できるけど、結構罠だった!)

ノードがいい感じに吸着したりするのも、この辺をしっかり理解していないとできません。
作ってる最中はあらぬ場所にすっとんでいったり、魔境でした💦

キーボードと同期させるのがしんどい

また今回の目標のひとつ、キーボードで動かせる、というのも地味に大変でした。
マウスやタッチ操作はクリックイベントなどで取得できますが、キーボードに対応するのであれば

  • 今どこが選択されているという余計な情報を抱える
  • アプリによって別のUIと操作を同期させなければならない
  • マウスとキーボードの両方で矛盾なく動かなければならない

こんな感じで、矛盾とバグのもぐら叩きを結構繰り返しましたね…。
キー要求イベントが外出しなのは、「別のUIと同期を取る」部分はアプリ側で処理する必要があると感じたからです。
Navigation? 上手く使える自信がナイ。

正直、私の想定外の部分で動きがおかしい、なんて事は全然あり得ると思います。
「ちゃんと動かねーよ!」という怒りをグッとこらえて、優しく問題点や、その現象(詳細)を教えていただけると幸いです。

修正は、前向きに考える

不具合いろいろ

とにかく色々ありましたが、やはり一番つまづいたのは「ScrollViewer や RectTransform をフワッとしか理解してない事による落とし穴」でしょうか。

今でも完全に理解しきれたとは言えませんが、位置ずれとか真剣に悩みましたね…。Content のアンカーを無意識に変えてしまい、沼にハマったり。

Content のアンカーは縦スクロール、横スクロールで設定すべき値が違うので、TableScrollViewer で矯正するようにしています。

すごくニッチな不具合で「スクロールバーで動かした後、キーで上下すると動きが怪しくなる」なんてのもありました。
ドラッグ(スワイプ)スクロールの後はおかしくならないのに…。

最初全然理由がわからなかったのですが、スクロールバーがトリガーになっていて、更に他のウィンドウにフォーカスすると正しく動くという現象を突き止め…スクロールバーの Navigation が Automatic になっているとキーボードで ScrollView が微妙に動かされていることを知りました。

TableScrollViewer 使用時は自動的に None になるよう変更しました。

また 10000 個(大量に)登録すると、標準のスクロールバーは Elastic な部分(上下の遊びの部分)の動きがおかしくなってしまう事もわかりました。
そもそもカックカクの動きになるので、そんなの気にスンナ! ってことなんでしょう。

このへんは TableScrollViewer では上手いこと動くように調整をかけておきました。

色々と(主に自分が原因で)苦労しましたが、それでもやはり、ScrollView は標準なのによく出来たコントロールだと感心することしきり。
作成中のゲームにも導入してみたり(いざ使ってみないと不具合は見えてこないので)、かなり時間をかけて取り組みました。

ScrollView といいながら、スクロールしない、縦横に並べるようなメニューでも使えるんですよね。
今後メニューの作成はだいぶ手間が省ける気がします。

メニューの操作感は UX に直結する重要な部分です。
その向上の助けになればいいのですが、作成したばかりの TableScrollViewer は色々と問題も抱えていることと思います。
その辺をご理解した上でご利用いただけると幸いです。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA