Posted at

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

More than 3 years have passed since last update.

このページは

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


その他(工事中)

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