uGUIのScroll Viewでページスクロール

  • 35
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

このページは
uGUIのScroll Viewをはじめてみる
uGUIのScroll ViewでGrid
を見ておくとよりわかりやすいかもです。
Unity5.3.1fで検証しました。

ページスクロールというのが、何かというとスマートフォンのHomeページをイメージするとわかりやすいでしょう。

例えばこんな感じで、薄い枠が実際に画面で、白いページが1ページ目、赤いページが2ページ目。
PageScroll.PNG

少し左にスワイプするとこんな感じ。それでここでスワイプをやめると...。
PageScroll1.PNG

こんな感じでスクロールが自動的に行われ、赤いページに吸着するようなイメージ。
中途半端なスクロール位置がないものかな?
PageScroll2.PNG

実装

初期配置

メニューバーの「GameOjbect」→「UI」→「Scroll View」を選択。
Scrollbarはいらないと思うので削除しておく。
PageScroll3.PNG

Inspectorはこんな感じ。

  • widthとHegithを500に調整
  • 横スクロール想定なのでHrizontalのチェックのみON

PageScroll4.PNG

Viewportの設定

わかりやすくするためMaskを外しておきます。
PageScroll5.PNG

Contentの設定

Anchorsを「stretch x stretch」
Pivotはド真ん中
Content Size Fitterのアタッチ(まだ値をいじらないでください)
Grid Layout Groupの「Padding」「Cell Size」をページがみやすいように設定
Constraintを「Fixed Row Count」
Constraint Countを「1」
PageScroll6.PNG

子にImageを3つ入れてみます
PageScroll7.PNG
こんな感じ。
灰色の背景があるところがGame画面で写るページです。MaskをONにすればよりわかりやすくなります。
Imageに色をつけてわかりやすくしています。
PageScroll8.PNG

それで先ほど設定していなかったContent Size Fitterの「Horizontal Fit」-「Preferred Size」にします。
PageScroll9.PNG
そうすると赤のImageが真ん中の初期表示となります。
別にこれでもいいんですが、左のImageからにしたかったので
PageScroll10.PNG

Content Size Fitterの「Horizontal Fit」-「Unconstained」に戻して、Left, Rightを0に戻したあと
Anchorsを「stretch x left」
Pivotは左真ん中
再度、Content Size Fitterの「Horizontal Fit」-「Preferred Size」
にします。下図のようになります。
PageScroll11.PNG
こんな感じ。
ここまでで普通のScroll Viewが完成
PageScroll12.PNG

Scroll Rectの改造

ScrollRectを継承して新しいScriptを作ってみます。
Scroll ViewにアッタチされているScrollRectを下記スクリプトに置き換えます。
設定が元に戻ってしまうので下図のように再設定します。
PageScroll13.PNG

PageScrollRect.cs
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

// ページスクロールビュー.
public class PageScrollRect : ScrollRect
{
    // 1ページの幅.
    private float pageWidth;
    // 前回のページIndex. 最も左を0とする.
    private int prevPageIndex = 0;

    protected override void Awake()
    {
        base.Awake();

        GridLayoutGroup grid = content.GetComponent<GridLayoutGroup>();
        // 1ページの幅を取得.
        pageWidth = grid.cellSize.x + grid.spacing.x;
    }

    // ドラッグを開始したとき.
    public override void OnBeginDrag(PointerEventData eventData)
    {
        base.OnBeginDrag(eventData);
    }

    // ドラッグを終了したとき.
    public override void OnEndDrag(PointerEventData eventData)
    {
        base.OnEndDrag(eventData);

        // ドラッグを終了したとき、スクロールをとめます.
        // スナップさせるページが決まった後も慣性が効いてしまうので.
        StopMovement();

        // スナップさせるページを決定する.
        // スナップさせるページのインデックスを決定する.
        int pageIndex = Mathf.RoundToInt(content.anchoredPosition.x / pageWidth);
        // ページが変わっていない且つ、素早くドラッグした場合.
        // ドラッグ量の具合は適宜調整してください.
        if (pageIndex == prevPageIndex && Mathf.Abs(eventData.delta.x) >= 5)
        {
            pageIndex += (int)Mathf.Sign(eventData.delta.x);
        }

        // Contentをスクロール位置を決定する.
        // 必ずページにスナップさせるような位置になるところがポイント.
        float destX = pageIndex * pageWidth;
        content.anchoredPosition = new Vector2(destX, content.anchoredPosition.y);

        // 「ページが変わっていない」の判定を行うため、前回スナップされていたページを記憶しておく.
        prevPageIndex = pageIndex;
    }
}

ページにスナップするな感じがわかるでしょうか。
PageScrollGif.gif

その他(工事中)

ピタッって吸着している感じなので、アニメーションなどで流れるように止まってほしいので、また後ほど調査してみます。