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点は消化。