2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Unity シンプルな仮想スクロール (uGUI)

Last updated at Posted at 2023-02-11

おことわり

この記事のコードには、新しい版 (GitHub)が存在します。

概要

  • 特徴
    • UnityEngine.UI.ScrollRectを継承しています。
      • 通常のScrollRectで動的に項目生成する場合と同じようにアセットを用意できます。
    • 個別に表示サイズが異なる「可変サイズの項目」に対応しています。
    • 縦/横並び、正/逆順、整列側(左/右、上/下)が選択できます。
    • 項目リストを動的に操作(挿入、削除、置換など)可能です。
  • 次のような使い方を想定しています。
    • UnityEngine.UI.ScrollRect(uGUI)の代替としてContent内にGameObjectを動的に生成します。
    • スクロール方向に対して、リストの前方にこれから表示される項目を追加し、表示の済んだリストの後方の項目を削除するなど、リストを動的に増減します。
    • 有限でも長大なリストを扱う際に、可視範囲外のGameObjectを節約します。
  • 次のような使い方はできません。
    • リストの上端と下端をループさせて、有限長のリストで無限にスクロールする。
    • 動的に生成される不定長のリストを自動的にスクロールする。

テスト環境

  • Unity 2022.3.6f1
  • Windows 11

アセットパッケージ

機能

  • リスト(IEnumerable<IInfiniteScrollItem>)の登録と初期化
    • 縦スクロール、または、横スクロール
    • 項目に対するパディングとスペーシング
    • スクロールに直行する方向の項目制御(下/左寄せ、中央寄せ、上/右寄せ、拡縮Fit)
    • 項目の並び順の反転
  • スクロール方向に可変長の項目サイズ
  • 項目リスト(List<IInfiniteScrollItem>)への任意の操作
  • UnityEngine.UI.ScrollRectの主要な機能

概念

  • スクロールレクト
    • 矩形のスクロール領域です。
    • 縦、または、横に項目が並び、スクロールします。
    • 可変長の項目を許容します。
  • 項目
    • 物理項目
      • スクロールレクトに縦または横に並んだ表示体です。
      • 物理項目は見える範囲にしか作られず、範囲外になった項目は不活性にされ、必要に応じて再利用されます。
      • 活性中の物理項目には、紐付けられている論理項目の内容が反映されます。
      • 一般に、プレファブとその制御クラスとして実装されます。
    • 論理項目
      • 物理項目に表示される値を保持するクラスです。
  • リスト
    • 論理項目の集合で、並び順を持ちます。
    • 配列やList(コレクション)として実装されます。

導入

  • プロジェクトにアセットパッケージInfiniteScrollRect.unitypackageを導入してください。
  • アセットの本体はAssets/InfiniteScroll/にあります。
    • フォルダを移動しても支障ありません。
    • フォルダの中は不用意に触らないようにしてください。
  • UI/Scroll Viewの代わりにUI/InfiniteScroll Viewを、UI/ScrollRectの代わりにUI/InfiniteScrollRectを使用します。
    • 必要に応じて、ScrollRectと共通の設定に加えて、PaddingSpacingChild AlignmentReverse ArrangementControl Child SizeStandard Item Sizeを設定してください。
    • Contentには何も置かないでください。
    • スクロール方向は縦/横のどちらかしか選べません。
  • インターフェイスIInfiniteScrollItemを継承したクラスを用意してください。
    • 必須のメソッドとプロパティの他に、コンストラクタなどを実装してください。
  • クラスInfiniteScrollItemComponentBaseを継承したクラスを用意してください。
    • static Create ()を置き換える(new)メソッドを実装してください。
      • このメソッドで項目の実体を生成するために、必要に応じて、クラスをアタッチしたプレファブを用意してください。
    • Initialize ()Apply ()overrideするメソッドの他に、Itemプロパティを実装してください。

使い方

  • InfiniteScrollRectコンポーネントのInitializeに、IInfiniteScrollItemを継承したクラスの配列またはリストを渡します。
    • このサンプルは、「GUI Text (Legacy)」を使用していますが、InfiniteScrollRectがそれに依存するわけではありません。
    • より具体的な使い方は、サンプルをご参照ください。
  • サンプルを確認するには、アセットパッケージInfiniteScrollSample.unitypackageを導入して、シーンAssets/Sample/Scenes/InfiniteScrollTest.unityを開いてください。
    • Assets/Sample/
      • Resouces/
        • Prefabs/
          • Item.prefab: 物理項目のプレファブ
      • Scenes/
        • InfiniteScrollTest.unity: サンプルシーン
      • Scripts/
        • InfiniteScrollTest.cs: サンプルメイン
        • Item.cs: IInfiniteScrollItemを継承した論理項目クラス
        • ItemComponent.cs: InfiniteScrollItemComponentBaseを継承した物理項目クラス

主なAPI

class InfiniteScrollRect

  • UnityEngine.UI.ScrollRectを継承したコンポーネント・クラスです。

フィールド

RectOffset padding

  • Contentと項目の間の隙間のサイズです。
  • インスペクタで設定可能な項目で、初期化の際に使われます。
    • 動的な変更後には再初期化が必要になります。

float spacing

  • 項目間の隙間のサイズです。
  • インスペクタで設定可能な項目で、初期化の際に使われます。
    • 動的な変更後には再初期化が必要になります。

TextAnchor childAlignment

  • スクロールに直行する方向の項目の整列制御です。
    • 下/左寄せ、中央寄せ、上/右寄せ
    • controlChildSizeが真の時は効果がありません。
  • インスペクタで設定可能な項目で、初期化の際に使われます。
    • 動的な変更後には再初期化が必要になります。

bool reverseArrangement

  • 項目の並び順を逆にします。
    • 偽だと、上から下、左から右になります。
    • 真だと、下から上、右から左になります。
  • インスペクタで設定可能な項目で、初期化の際に使われます。
    • 動的な変更後には再初期化が必要になります。

bool controlChildSize

  • スクロールに直行する方向の項目の拡大制御です。
    • 真だと、項目が幅いっぱいに拡大されて、childAlignmentの設定は無効になります。
  • インスペクタで設定可能な項目で、初期化の際に使われます。
    • 動的な変更後には再初期化が必要になります。

float standardItemSize

  • アイテムのスクロール方向の標準的なサイズです。
  • 未だ物理項目が作られていない場合に、仮のサイズとして使用します。
    • 実体に近いサイズに設定することで、表示のガタツキを減らせます。
  • インスペクタで設定可能な項目で、初期化の際に使われます。
    • 動的な変更後には再初期化が必要になります。

プロパティ

bool Valid

  • スクロールレクトが有効に初期化されていれば真です。

IInfiniteScrollItem this [int index]

  • 論理項目リストにアクセスするインデクサです。

int Count

  • 論理項目の数です。

int FirstIndex

  • 表示中の最初の論理項目のインデックスです。

int LastIndex

  • 表示中の最後の論理項目のインデックスです。

メソッド

void Initialize (IEnumerable<IInfiniteScrollItem> items, int index = 0)

  • 論理項目のリストitemsを渡してスクロールレクトを初期化します。
    • indexは最初に表示する項目のインデックスです。
  • インスペクタで設定可能なシリアライズ・フィールドは、あらかじめ設定しておく必要があります。
    • シリアライズフィールドの変更後には再初期化が必要になります。

ReadOnlyCollection<IInfiniteScrollItem> AsReadOnly ()

  • 内部の論理項目リストにアクセスします。

List<IInfiniteScrollItem> FindAll (Predicate<IInfiniteScrollItem> match)

  • 条件に合う論理項目を抽出したリストを返します。

List<TOutput> ConvertAll<TOutput> (Converter<IInfiniteScrollItem, TOutput> converter)

  • 論理項目を変換したリストを返します。

void Clear ()

  • 全項目を抹消します。

void Modify (Action<InfiniteScrollRect, List<IInfiniteScrollItem>, int, int> modifier)

  • 項目リストの書き換えを行います。
  • modifierには、スクロールレクト、論理項目のリスト、表示中の最初の論理項目のインデックス、表示中の最後の論理項目のインデックスが渡されます。
  • 論理項目のリストを自在に更新することができますが、表示中の項目の削除など、変更の内容によってはスクロールが生じます。

Interface IInfiniteScrollItem

  • 論理アイテムのベースとなるインターフェイスです。
  • このクラスを継承したクラスを作成して、論理項目リストList<IInfiniteScrollItem>として使用します。
    • メソッドCreate ()といくつかのプロパティは必須で、他にコンストラクタなどを実装します。

プロパティ

float Position

  • Content上に配置される際のスクロール方向のオフセットです。

float Size

  • Content上に配置される際のスクロール方向のサイズです。

bool Dirty

  • 上記のオフセットとサイズを除く論理項目の内容に変更があって、物理項目に反映する必要が生じていることを表します。
  • 物理項目側で、このフラグを監視して内容の取得と反映を行います。

メソッド

InfiniteScrollItemComponentBase Create (InfiniteScrollRect scrollRect, int index)

  • 親のスクロールレクトと論理項目リストのインデックスを受け取って、この論理項目をスクロールレクトに表示するための物理項目を生成するメソッドで、overrideが必要です。
    • 実際の生成は、物理項目のクラスに委ねて、このメソッドは受け渡しをするだけです。
  • 物理項目は、渡されたインデックスを用いて論理項目にアクセスします。

class InfiniteScrollItemComponentBase

  • 物理アイテムのベースとなる抽象クラスです。
  • このクラスを継承したクラスを作成して、物理項目のGameObjectにアタッチして使用します。
    • static Create ()の置き換え(new)は必須です。置き換えが行われていない場合は、実行時に例外を投げます。
    • 独自の情報を扱うなら、Initialize ()Apply ()overrideは必須で、他にItemプロパティの実装も必要です。

プロパティ

Item

  • リンク中の論理項目にアクセスするためのプロパティで、置き換え(new)が必要です。

メソッド

static InfiniteScrollItemComponentBase Create (InfiniteScrollRect scrollRect, int index)

  • 論理項目から呼ばれて物理項目を生成するメソッドで、置き換え(new)が必要です。
  • このメソッドは継承したクラスでの置き換えを前提としたもので、参考のために実装されています。

void Initialize ()

  • 生成直後に初期化するためのメソッドでoverrideが必要です。

void Apply ()

  • 生成直後、および、論理項目の内容に変更があった(Dirty)ときに、内容を反映するためのメソッドで、overrideが必要です。
  • 基底クラスのメソッドでDirtyfalseにされます。

おわりに

説明が解りづらい、使いにくい、これがしたい、など何でも、コメントをお寄せいただけるとありがたいです。
最後までお読みいただきありがとうございました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?