コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity】UI で入れ子のスクロールを実装する時に使用するコンポーネント

ソースコード

using System;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Kogane.Internal
{
    /// <summary>
    /// 入れ子のスクロールを実装する時に使用するコンポーネント
    /// 子の ScrollRect の代わりにこの NestedScrollRect を使用する
    /// </summary>
    [DisallowMultipleComponent]
    internal sealed class NestedScrollRect : ScrollRect
    {
        //================================================================================
        // 変数
        //================================================================================
        private ScrollRect m_parentScrollRect;
        private bool       m_sendToParent;

        //================================================================================
        // プロパティ
        //================================================================================
        private ScrollRect ParentScrollRect =>
            m_parentScrollRect ??=
                GetComponentsInParent<ScrollRect>()
                    .First( x => x != this );

        //================================================================================
        // 関数
        //================================================================================
        /// <summary>
        /// ドラッグを開始した時に呼び出されます
        /// </summary>
        public override void OnBeginDrag( PointerEventData eventData )
        {
            var delta = eventData.delta;
            var x     = delta.x;
            var y     = delta.y;

            m_sendToParent =
                horizontal && Math.Abs( x ) < Math.Abs( y ) ||
                vertical && Math.Abs( y ) < Math.Abs( x );

            if ( m_sendToParent )
            {
                ParentScrollRect.OnBeginDrag( eventData );
            }
            else
            {
                ParentScrollRect.velocity = Vector2.zero;
                base.OnBeginDrag( eventData );
            }
        }

        /// <summary>
        /// ドラッグ中に呼び出されます
        /// </summary>
        public override void OnDrag( PointerEventData eventData )
        {
            if ( m_sendToParent )
            {
                ParentScrollRect.OnDrag( eventData );
            }
            else
            {
                base.OnDrag( eventData );
            }
        }

        /// <summary>
        /// ドラッグを終了した時に呼び出されます
        /// </summary>
        public override void OnEndDrag( PointerEventData eventData )
        {
            if ( m_sendToParent )
            {
                ParentScrollRect.OnEndDrag( eventData );
            }
            else
            {
                base.OnEndDrag( eventData );
            }

            m_sendToParent = false;
        }
    }
}