【Unity】縦と横で操作するスクロールビューを切り替える

概要

漫画アプリとかでよくある縦にスクロールが出来て、横にスライドするとアイテムを削除できるようなスクロールビューです。

ScrollRectを拡張してデフォルトのScrollRectと差し換えて使用します。

サンプル

GitHub:https://github.com/Okamochi000/OverlapScroll

実証環境

  • OS:Windows
  • Unityバージョン:2020.3.0f1

実装サンプルコード

OverlapScroll.cs

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

/// <summary>
/// スクロール領域が重なるときScrollRect制御
/// </summary>
public class OverlapScrollRect : ScrollRect
{
    private enum ScrollType
    {
        NotDrag,   // ドラッグされていない
        Self,      // 自身
        Back       // 裏
    }

    private ScrollRect backScrollRect_ = null;
    private ScrollType scrollType_ = ScrollType.NotDrag;

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

        // 裏のScrollRectを強制的にドラッグ解除する
        if (scrollType_ == ScrollType.Back)
        {
            PointerEventData eventData = new PointerEventData(null);
            eventData.button = PointerEventData.InputButton.Left;
            backScrollRect_.OnEndDrag(eventData);
            scrollType_ = ScrollType.NotDrag;
        }
    }

    /// <summary>
    /// 裏にあるScrollRectの設定
    /// </summary>
    public void SetBackScrollRect(ScrollRect scrollRect)
    {
        backScrollRect_ = scrollRect;
    }

    public override void OnDrag(PointerEventData eventData)
    {
        // スクロール対象確認
        ScrollType prevScrollType = scrollType_;
        if (backScrollRect_ == null) { scrollType_ = ScrollType.Self; }
        if (scrollType_ == ScrollType.NotDrag)
        {
            if (vertical == horizontal)
            {
                scrollType_ = ScrollType.Self;
            }
            else if (vertical)
            {
                if (Mathf.Abs(eventData.delta.x) < Mathf.Abs(eventData.delta.y)) { scrollType_ = ScrollType.Self; }
                else { scrollType_ = ScrollType.Back; }
            }
            else if (horizontal)
            {
                if (Mathf.Abs(eventData.delta.x) > Mathf.Abs(eventData.delta.y)) { scrollType_ = ScrollType.Self; }
                else { scrollType_ = ScrollType.Back; }
            }
        }

        // 裏をスクロールする場合にScrollRectの値をコピー
        if (prevScrollType == ScrollType.NotDrag && scrollType_ == ScrollType.Back)
        {
            // 裏のScrollRectを強制的にドラッグ開始する
            backScrollRect_.OnBeginDrag(eventData);
        }
        else
        {
            if (scrollType_ == ScrollType.Back) { backScrollRect_.OnDrag(eventData); }
            else { base.OnDrag(eventData); }
        }
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
        base.OnEndDrag(eventData);

        // 裏のScrollRectを強制的にドラッグ解除する
        if (scrollType_ == ScrollType.Back) { backScrollRect_.OnEndDrag(eventData); }

        scrollType_ = ScrollType.NotDrag;
    }
}

ScrollSetting.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// スクロール初期設定
/// </summary>
public class ScrollSetting : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        ScrollRect scrollRect = this.GetComponent<ScrollRect>();
        OverlapScrollRect[] overlapScrollRects = this.GetComponentsInChildren<OverlapScrollRect>();
        foreach (OverlapScrollRect overlapScrollRect in overlapScrollRects) { overlapScrollRect.SetBackScrollRect(scrollRect); }
    }
}

サンプルコード解説

内側のスクロールビューのScrollRectコンポーネントをOverlapScroll.csに差し替えて、OverlapScroll.SetBackScrollRect(ScrollRect)に外側のScrollRectを設定します。

ScrollSetting.csはSetBackScrollRectを呼び出すサンプルコードです。

スクロールビューの内側にスクロールビューを入れると内側のUIだけドラッグされるため、外側のスクロールビューは操作できなくなります。そのため、このスクリプトでは強制的にドラッグイベントを呼び出して操作しています。

アイテムをドラッグした状態で左右にスライドすると離すまで左右スライドのみスクロールされるようになり、縦にスライドすると離すまで縦スライドのみスクロールされるようになります。

   

コメントを残す


CAPTCHA