【Unity】固定ヘッダー付きのScrollViewを作成する

Unity で、固定ヘッダー付きのScrollViewを作成します。

スクロールバーでコンテンツを移動させても、上側、左側のヘッダーの位置は固定となってます。

やり方はいろいろあると思いますが、私が実装した方法を書きます。

大事なことは、スクロールバー移動のイベントを受け取ったとき、ヘッダーの位置が動かないようにポジションを上書きすることです

今回作成したプロジェクトは以下のリンクからダウンロードできます。

GitHub
GitHub - HomeProgrammer81/ScrollViewHeader at main_ScrollViewHeader Contribute to HomeProgrammer81/ScrollViewHeader development by creating an account on GitHub.
開発環境
  • Windows10 Home 64bit
  • Unity Version 2020.3.17f1 Personal
  • Visual Studio Community 2019  16.11.2
目次

ScrollView の設定

ScrollView を使用します。GameObject→UI→ScrollView で追加できます。

ScrollView のパラメータ

  • Rect Transform のWidth、Heightを設定します。
  • Scroll Rect コンポーネントのMovement Type をClamped に変更します

ゲームオブジェクトの順番は、Panel_Cell、Panel_ColumnHeader、Panel_RowHeader、Panel_Header の順番は変更しません。スクロールしたとき、GameObjectの上から順に上書きするからです

Content 以下の構成

Scroll View のContent 以下の構成です。Contentの子Panel、それ以降の子はすべてGameObject→UI→Panel で設定します。

Panel

Contentと同じ領域。背景を白にする。

Panel_Cell

全セルのルート。

Panel_Cell_Org

Cell のコピー元です。スクリプトでコピーして使います。

Panel_ColumnHeader

列ヘッダーのルートです。スクリプトにて、このオブジェクトの子にヘッダーを追加します。

Panel_ColumnHeader_Org

列ヘッダーのパネルのコピー元です。スクリプトでコピーして使います。

Panel_RowHeader

Panel_RowHeader_Org

行ヘッダーのパネルのコピー元です。スクリプトでコピーして使います。

Panel_Header

左上の黒いところのパネルです。

ScrollView のコンポーネントに設定するスクリプト

ScrollView に設定するコードです。

このスクリプトは、ScrollView オブジェクトにコンポーネントとして追加します。

また、ScrollView_Horizontal、ScrollView_Vertical 関数は、それぞれScrollbar Horizontal、ScrollView_Vertical オブジェクトのScrollbar コンポーネント→On Value Changed に設定します。

using UnityEngine;
using UnityEngine.UI;

namespace Assets
{
    // スクロールビューコントローラー
    class ScrollViewController : MonoBehaviour
    {
        private GameObject viewport;
        private GameObject content;
        private GameObject panel;
        private GameObject header;
        private GameObject columnHeader;
        private GameObject rowHeader;
        private GameObject cell;

        // 開始
        private void Start()
        {
            viewport = transform.Find("Viewport").gameObject;
            content = viewport.transform.Find("Content").gameObject;
            panel = content.transform.Find("Panel").gameObject;

            header = panel.transform.Find("Panel_Header").gameObject;
            columnHeader = panel.transform.Find("Panel_ColumnHeader").gameObject;
            rowHeader = panel.transform.Find("Panel_RowHeader").gameObject;

            cell = panel.transform.Find("Panel_Cell").gameObject;

            float cellWidth = header.GetComponent<RectTransform>().sizeDelta.x;
            float cellHeight = header.GetComponent<RectTransform>().sizeDelta.y;

            // 列ヘッダー数10
            for ( int i = 0; i<10; i++)
            {
                GameObject columnHeaderChild = GameObject.Instantiate(columnHeader.transform.Find("Panel_ColumnHeader_Org")).gameObject;
                columnHeaderChild.transform.parent = columnHeader.transform;
                columnHeaderChild.transform.localPosition = new Vector2(i * cellWidth, 0);

                Text text = columnHeaderChild.transform.Find("Text").GetComponent<Text>();
                text.text = "Column" + (i + 1);

                columnHeaderChild.name = "Column" + (i + 1);
                columnHeaderChild.SetActive(true);
            }

            // 行ヘッダー数15
            for (int j = 0; j < 15; j++)
            {
                GameObject rowHeaderChild = GameObject.Instantiate(rowHeader.transform.Find("Panel_RowHeader_Org")).gameObject;
                rowHeaderChild.transform.parent = rowHeader.transform;
                rowHeaderChild.transform.localPosition = new Vector2(0, -j * cellHeight);

                Text text = rowHeaderChild.transform.Find("Text").GetComponent<Text>();
                text.text = "Row" + (j + 1);

                rowHeaderChild.name = "Row" + (j + 1);
                rowHeaderChild.SetActive(true);
            }

            // セル 10×15
            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 15; j++)
                {
                    GameObject cellChild = GameObject.Instantiate(cell.transform.Find("Panel_Cell_Org")).gameObject;
                    cellChild.transform.parent = cell.transform;
                    cellChild.transform.localPosition = new Vector2(i * cellWidth, -j * cellHeight);

                    Text text = cellChild.transform.Find("Text").GetComponent<Text>();
                    text.text = "Cell" + (i + 1) + (j + 1);

                    cellChild.name = "Cell" + (i + 1) + (j + 1);
                    cellChild.SetActive(true);
                }
            }

            content.GetComponent<RectTransform>().sizeDelta = new Vector2(cellWidth * (1 + 10), cellHeight * (1 + 15));
        }

        // 水平スクロールバー移動
        public void ScrollView_Horizontal(float value)
        {
            float yContent = content.GetComponent<RectTransform>().anchoredPosition.y;

            float contentWidth = content.GetComponent<RectTransform>().rect.width;
            float viewportWidth = viewport.GetComponent<RectTransform>().rect.width;

            float diff = (contentWidth - viewportWidth) * value;
            if (diff < 0)
            {
                diff = 0;
            }

            float cellHeight = header.GetComponent<RectTransform>().sizeDelta.y;
            rowHeader.GetComponent<RectTransform>().anchoredPosition = new Vector2(diff, -cellHeight);

            header.GetComponent<RectTransform>().anchoredPosition = new Vector2(diff, -yContent);

        }

        // 垂直スクロールバー移動
        public void ScrollView_Vertical(float value)
        {
            float xContent = content.GetComponent<RectTransform>().anchoredPosition.x;

            float contactHeight = content.GetComponent<RectTransform>().rect.height;
            float viewportHeight = viewport.GetComponent<RectTransform>().rect.height;

            float diff = (contactHeight - viewportHeight) * (1-value);
            if (diff < 0)
            {
                diff = 0;
            }

            float cellWidth = header.GetComponent<RectTransform>().sizeDelta.x;
            columnHeader.GetComponent<RectTransform>().anchoredPosition = new Vector2(cellWidth, -diff);

            header.GetComponent<RectTransform>().anchoredPosition = new Vector2(-xContent, -diff);
        }
    }
}

Start 関数

実行時に呼ばれる関数です。

ここでは、ヘッダー、セルを生成しています。今回は、10列×15行のヘッダー、セルを作成しました。Content の幅、高さをテーブル全体と一致させます

Content の領域が、スクロールバーでスクロールできる範囲となります。

Start関数実行後は、↓の表が表示されます。

ScrollView_Horizontal、ScrollView_Vertical 関数

それぞれ、水平スクロールバー、垂直スクロールバーが移動したときに呼ばれます。

ここでは、スクロールバーの位置に合わせて、ヘッダーの位置がViewport の位置から変化しないようにしてます。なので、スクロールバーの位置に対し、ヘッダーの固定位置を再計算し、ヘッダー位置を上書きしています。

この方法で、ヘッダー位置を固定して見せることができます。

 まとめ

今回は、Unity のScrollView で固定ヘッダー付きのScrollViewを作成する方法を説明しました。大事なことは、スクロールバーのイベントを受け取ったとき、ヘッダーの位置が動かないようにポジションを上書きすることです

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次