【Unity】uGUIでスクロールビューを実装するならコレ!Enhanced Scrollerをサクッと使う

Asset Storeで販売されている高機能なスクロールビューを実装できるアセットであるEnhanced Scrollerの基本的な使い方を紹介します。

Unity2018.3.9

Enhanced Scroller?

Enhanced ScrollerはAsset Storeで販売されているアセットです。

assetstore.unity.com

スクロールビューのセルのViewをプーリングしてパフォーマンスを向上させたり、
Pull-to-Refreshやページングなどが簡単に実装出来たりと高機能なスクロールビューを実現できます。

これらの機能は独自で実装すると地味に大変だし、
仕様追加に伴いおかしな方向に拡張されがちなので、
最初からライブラリを使ってしまったほうがいいと個人的には思っています。

Hierarchyをセットアップする

Enhanced Scrollerを使うためにまずはHierarchyをセットアップします。

まず適当なuGUIのGameObjectを作って下記の三つのコンポーネントをアタッチします。

  • Enhanced Scroller
  • Image
  • Mask

Inspectorは下記のような感じになります。
Scroll RectはEnhanced Scrollerと一緒に貼られます。

f:id:halya_11:20190406170559p:plain

次にその子としてGameObjectを作ります。
名前は何でもいいですが今回はView Container(Temporary)としました。
そしてこのGameObjectをScroll RectのContentに代入します。

f:id:halya_11:20190406171022p:plain

そしてこのView Containerの下にセルのViewを作っていきます。
この時、セルのViewは縦横ともStretchにして、大きさは親であるView Containerで調整します。

f:id:halya_11:20190406171355p:plain

View Containerはランタイムで使われるものではない(レイアウト用)なので、
セルを調整しやすいサイズに変更してしまって問題ありません。

今回はシンプルなボタンをセルのViewとして作成しました。
このViewはPrefab化しておきます。

f:id:halya_11:20190407231546p:plain

最後にControllerという名前のGameObjectをルートオブジェクトとして作っておきます。

f:id:halya_11:20190407231345p:plain

スクリプトを作成する

Hierarchyのセットアップが終わったらスクリプトを作っていきます。
Enhanced ScrollerはMVCアーキテクチャを前提として設計されています。

まずセルのデータを保持するためのクラスを作ります。

public class ExampleCellData
{
    public string message;
}

次にこのデータを使いセルのViewを作ります。

using EnhancedUI.EnhancedScroller;
using System;
using UnityEngine;
using UnityEngine.UI;

public class ExampleCellView : EnhancedScrollerCellView
{
    [SerializeField]
    private Text _text;
    [SerializeField]
    private Button _button;

    public Action<ExampleCellView> onClick;

    public void SetData(ExampleCellData data)
    {
        _text.text = data.message;
    }

    private void Awake()
    {
        _button.onClick.AddListener(() => onClick?.Invoke(this));
    }
}

セルのViewクラスはEnhancedScrollerCellViewを継承する必要があります。
また、先ほど作ったデータをSetDataで渡しています。

このコンポーネントは前節でPrefab化したGameObjectにアタッチしてTextの参照を持たせておきます。

f:id:halya_11:20190407224023p:plain

Cell IdentifierにはExample Cell Viewと入力しておきます。
これは、複数の種類のセルを扱うときの識別子となります。

最後にIEnhancedScrollerDelegateを実装したControllerを作ります。

using EnhancedUI.EnhancedScroller;
using System.Collections.Generic;
using UnityEngine;

public class ExampleController : MonoBehaviour, IEnhancedScrollerDelegate
{
    private List<ExampleCellData> _data;

    [SerializeField]
    private EnhancedScroller _scroller;
    [SerializeField]
    private ExampleCellView _cellViewPrefab;

    private void Start()
    {
        // データを作成
        _data = new List<ExampleCellData>();
        for (int i = 0; i < 30; i++) {
            _data.Add(new ExampleCellData { message = "cell " + i });
        }

        _scroller.cellViewVisibilityChanged += view =>
        {
            if (view.active)
            {
                // セルが表示状態になった時の処理
                var cellView = (ExampleCellView)view;
                cellView.SetData(_data[view.dataIndex]);
            }
        };
            
        // セルがインスタンス化されたときの処理
        _scroller.cellViewInstantiated += (scroller, view) =>
        {
            var cellView = (ExampleCellView)view;
            cellView.onClick = x => Debug.Log("Clicked: " + x.dataIndex);
        };

        // Scrollerにデリゲート登録
        _scroller.Delegate = this;
        // ReloadDataをするとビューが更新される
        _scroller.ReloadData();
    }

    // セルの数を返す
    public int GetNumberOfCells(EnhancedScroller scroller)
    {
        return _data.Count;
    }

    // セルのサイズ(縦幅or横幅)を返す
    public float GetCellViewSize(EnhancedScroller scroller, int dataIndex)
    {
        return 50;
    }

    // セルのViewを返す
    public EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex)
    {
        // Scroller.GetCellView()を呼ぶと新規生成orリサイクルを自動的に行ったViewを返してくれる
        return scroller.GetCellView(_cellViewPrefab);
    }
}

細かい説明はコメントに書きました。
IEnhancedScrollerDelegateを実装し、それをScrollerに登録しています。

このコンポーネントはScrollerにアタッチし、
ScrollerにEnhanced Scrollerを、Cell View PrefabにセルをPrefab化したものを持たせます。

f:id:halya_11:20190407234013p:plain

セットアップ完了&再生

以上でセットアップは完了です。
この状態で再生すればスクロールビューが動作していることを確認できます。

f:id:halya_11:20190407234214g:plain

セルのサイズは個別に設定できる

ここからは少しだけ応用的な使い方を紹介します。

まず、ControllerのGetCellViewSize()はセルごとに設定できます。
つまりセルのサイズは自由に設定できます。

f:id:halya_11:20190407235824p:plain

セルのViewは複数設定できる

またControllerのGetCellView()もセルごとに設定できます。
つまり、複数のPrefabを一つのスクロールビューに使うことができます。

f:id:halya_11:20190408000225p:plain

セルのデータを更新する

セルのデータを更新するには、データを書き換えてからEnhancedScroller.RefreshActiveCellViews()を呼びます。
このメソッドは現在表示されている部分だけを処理するので効率が良いです。

ただしセルのサイズの再評価は行わないので、セルサイズも変わるようなデータ更新には対応できません。
そのようなケースでは代わりにEnhancedScroller.ReloadData()を使います。

ループ

Enhanced ScrollerのLoopプロパティにチェックを入れるとループさせることができます。

f:id:halya_11:20190407234652p:plain

こんな感じで一番最後の要素の後にまた最初の要素が表示されループするようになります。

f:id:halya_11:20190407234902g:plain

ジャンプ

特定の要素にジャンプするにはEnhancedScroller.JumpToDataIndex()を使います。
イージングや秒数も指定出来て非常に便利です。

_scroller.JumpToDataIndex(20, 0, 0, true, EnhancedScroller.TweenType.easeInSine, 1)

f:id:halya_11:20190407235649g:plain