uGUIのGridLayoutGroupで子要素を使い回し

Unity5のuGUIいいですね。
まだ暇な時間に標準機能を弄ってるだけなのですが、
特にスクロールリストが使いやすくて好きです。

今回はリストの要素を使いまわしして
高速に動作するリストコンポーネントが欲しい。
と感じたので作ってみました。

ただ、使い回しリストを作るだけだと二番煎じ感が強いので、
+αで非同期処理が入る場面も想定しての造りにしようと思います。

例えば、ソシャゲなどでよくあるキャラクター選択画面で
顔アイコンがずらりと並ぶ場面などで、
画像を読み込みながらスクロールしていくような感じですね。

予測される例外処理

可視範囲に入った瞬間に読み込み処理が入って
読み込みが終わる前に場所で使い回されてしまうと、
実装次第ではうまく表示されないなどの状態も予想されます。

要は、非同期処理の穴ですね。
読み込み中の要素は使い回さず、事が済むまで放置するように処理します。

もちろん、自分が一人で作っている分には
問題にすぐ気づけるので良いのですが、
複数人での開発となると話は別。

使ってもらう側としても、もっと気軽に、
もっと気持ちよくコーディングしてもらいたいものです。

プロトタイプ作ってみました

f:id:SprField:20170326212207g:plain

GIFアニメーションだとカクカクして分かりづらいかもしれませんが、一千個、一万個のオブジェクトも難なくスクロールする様を見るのは小気味よいですね。

github.com

 

 使い方

  1. Hierarchyで右クリック
  2. UI > Scroll View を選択
  3. Content オブジェクトに RecycleGridLayoutGroupコンポーネントを追加
  4. RecycleGridLayoutGroupコンポーネントに設定を入力
  5. 任意でソースコードから onVisibleListItem、onHideListItem にコールバック処理を記述する

以下、onVisibleListItem、onHideListItemコールバックのサンプル

void Start()
{
    RecycleGridLayoutGroup grid = target.GetComponent<RecycleGridLayoutGroup>();
    // リストの総数を設定
    grid.listItemCount = 1000;
    // コールバックイベントの設定
    grid.onVisibleListItem = OnVisibleListItem;
    grid.onHideListItem = OnHideListItem;
}

/// 対象のリスト要素が画面内に入った直後のコールバック
/// 引数 item には対象のリストの情報が入ったコンポーネント
/// complete は処理が完了したら必ず呼ぶこと(呼ばれるまで使いまわしの対象にならない)
private void OnVisibleListItem( ListItemContent item, Action complete )
{
    // item.indexでリストの何番目かをとってこれるので、データベースの参照などに
    Debug.Log( "リスト"item.index + "番目" );
    // ルートオブジェクトについたコンポーネントなのでFindChildで子要素を検索が可能
    RawImage img = item.transform.FindChild("icon").GetComponent<RawImage>();

    // キャラクターアイコンのテクスチャを読み込む処理があったとして・・・
    LoadCharacterIconTexture( chara_id, ( tex ) => {
        img.texture = tex;
        complete(); // 処理が終わったら必ず呼ぶ
    });
}

/// 対象のリスト要素が画面外に出ていった直後の処理
private void OnHideListItem( ListItemContent item )
{
    // 必要なら画面外に消えていった際の処理を書く
}


画像は読み込んでませんがランダムな時間に
プログレスが100%になる処理を入れてやってみました。
ちゃんと動いているみたいですね。よかったよかった。

f:id:SprField:20170327234555g:plain

残課題、未実装項目

こういうブログ書くの慣れてないもので、まとめるだけで時間かかっちゃいましたが
残課題まとめておきます。消化したら順次打ち消し線入れていきます。

  • View全体を更新する関数を用意するの忘れてた
  • 末尾以外の要素が削除/追加された場合の処理(上記、全体更新の処理を入れてやる必要がある)
  • 上から下方向へのスクロールしか出来ない

3番目は気が向いたらやります。多分。

ご意見ご要望などがございましたらどうぞお気軽に~

 

―― 更新履歴 ――

2017/03/28更新。とりあえず2点は消化。

2017/09/26更新

リストアイテムのピボットが左上前提で作られていたので修正しました。

他、newしたGameObjectをInstantiateするなど、

無駄なオブジェクトが残ったままだったのを修正しました。