uGUI スクロールビューを分割毎にスナップする


放置でしたが、最新のUnityに合わせて、更新しました。

ScrollRectSnap

ScrollRectにはページング機能やスナップ機能は付いてなかったので、デザイナーなりに考えた。

  • スクロール位置はnormalizedPositionから0f〜1fで取得/入力できるので、各ページ位置は以下で取得。

    ページ数/ページ総数

  • スクロール位置と各ページ間の中間地点比較して、越えていたら次ページ位置をスナップ位置に指定

    ページ間の中間地点
    (2*ページ数-1)/((ページ総数-1)*2)

  • スナップモーションはVector2.Lerpで。

スクリプト

ScrollRectSnap.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class ScrollRectSnap : ScrollRect {
    public int horizontalPages = 3; // horizontalの分割数
    public int verticalPages = 3;  // verticalの分割数

    [SerializeField] private float smooth = 10f;  // スナップ係数
    private Vector2 targetPosition; // スナップ先座標
    private bool isDrag = false; // フラグ

    protected override void Start(){
        base.Start ();
        normalizedPosition = content.GetComponent<RectTransform> ().pivot;
        targetPosition = FindSnapPosition ();
    }

    void Update(){
        if (!isDrag && normalizedPosition != targetPosition) {
            normalizedPosition = Vector2.Lerp (normalizedPosition, targetPosition, smooth * Time.deltaTime);
        }
    }

    public override void OnBeginDrag(PointerEventData eventData){
        base.OnBeginDrag (eventData);
        isDrag = true;
    }

    public override void OnEndDrag(PointerEventData eventData){
        base.OnEndDrag (eventData);
        targetPosition = FindSnapPosition ();
        isDrag = false;
    }

    // スナップ先座標を取得する
    Vector2 FindSnapPosition(){
        float x = 0, y = 0;
        Vector2 center;

        if(horizontal){
            if(horizontalPages > 1){
                for (int page = 0; page < horizontalPages; page ++) {
                    center.x = (2f * page - 1f) / ((horizontalPages - 1f) * 2f);
                    if(horizontalNormalizedPosition >= center.x){
                        x = page / (horizontalPages - 1f);
                    }
                }
            }
        }else{
            x = horizontalNormalizedPosition;
        }

        if(vertical){
            if(verticalPages > 1){
                for (int page = 0; page < verticalPages; page ++) {
                    center.y = (2f * page - 1f) / ((verticalPages - 1f) * 2f);
                    if(verticalNormalizedPosition >= center.y){
                        y = page / (verticalPages - 1f) ;
                    }
                }
            }
        }else{
            y = verticalNormalizedPosition;
        }
        return new Vector2 (x, y);
    }
}

上記だけだと追加したpublic変数がInspectorに表示されないので、以下をAssets/Editorに追加

ScrollRectSnapEditor.cs
using UnityEngine;
using UnityEditor;

[CustomEditor( typeof(ScrollRectSnap))]
public sealed class ScrollRectSnapEditor : Editor {

    public override void OnInspectorGUI(){
        DrawDefaultInspector ();
    }
}

使い方

  • ScrollRect の代わりに上記スクリプトをコンポーネントに追加。
  • Horizontal Pages に水平方向のページ総数を入力 (Horizontal がオンになっていないと効かない)
  • Vertical Pages に垂直方向のページ数を入力 (Vertical がオンになっていないと効かない)
  • Smoothでスナップモーションを調整