1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465 |
- using System;
- using UnityEngine;
- using UnityEngine.Events;
- using UnityEngine.EventSystems;
- using UnityEngine.UI;
- namespace Rokid.UXR.Interaction
- {
- /// <summary>
- /// Override By UGUI ScrollRect
- /// </summary>
- [AddComponentMenu("UI/RKScroll Rect", 37)]
- [SelectionBase]
- [ExecuteAlways]
- [DisallowMultipleComponent]
- [RequireComponent(typeof(RectTransform))]
- /// <summary>
- /// A component for making a child RectTransform scroll.
- /// </summary>
- /// <remarks>
- /// ScrollRect will not do any clipping on its own. Combined with a Mask component, it can be turned into a scroll view.
- /// </remarks>
- public class UGUIScrollRect : UIBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler, ICanvasElement, ILayoutElement, ILayoutGroup
- {
- /// <summary>
- /// A setting for which behavior to use when content moves beyond the confines of its container.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- /// public Scrollbar newScrollBar;
- ///
- /// //Called when a button is pressed
- /// public void Example(int option)
- /// {
- /// if (option == 0)
- /// {
- /// myScrollRect.movementType = ScrollRect.MovementType.Clamped;
- /// }
- /// else if (option == 1)
- /// {
- /// myScrollRect.movementType = ScrollRect.MovementType.Elastic;
- /// }
- /// else if (option == 2)
- /// {
- /// myScrollRect.movementType = ScrollRect.MovementType.Unrestricted;
- /// }
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public enum MovementType
- {
- /// <summary>
- /// Unrestricted movement. The content can move forever.
- /// </summary>
- Unrestricted,
- /// <summary>
- /// Elastic movement. The content is allowed to temporarily move beyond the container, but is pulled back elastically.
- /// </summary>
- Elastic,
- /// <summary>
- /// Clamped movement. The content can not be moved beyond its container.
- /// </summary>
- Clamped,
- }
- /// <summary>
- /// Enum for which behavior to use for scrollbar visibility.
- /// </summary>
- public enum ScrollbarVisibility
- {
- /// <summary>
- /// Always show the scrollbar.
- /// </summary>
- Permanent,
- /// <summary>
- /// Automatically hide the scrollbar when no scrolling is needed on this axis. The viewport rect will not be changed.
- /// </summary>
- AutoHide,
- /// <summary>
- /// Automatically hide the scrollbar when no scrolling is needed on this axis, and expand the viewport rect accordingly.
- /// </summary>
- /// <remarks>
- /// When this setting is used, the scrollbar and the viewport rect become driven, meaning that values in the RectTransform are calculated automatically and can't be manually edited.
- /// </remarks>
- AutoHideAndExpandViewport,
- }
- [Serializable]
- /// <summary>
- /// Event type used by the ScrollRect.
- /// </summary>
- public class ScrollRectEvent : UnityEvent<Vector2> { }
- [SerializeField]
- protected RectTransform m_Content;
- /// <summary>
- /// The content that can be scrolled. It should be a child of the GameObject with ScrollRect on it.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- /// public RectTransform scrollableContent;
- ///
- /// //Do this when the Save button is selected.
- /// public void Start()
- /// {
- /// // assigns the contect that can be scrolled using the ScrollRect.
- /// myScrollRect.content = scrollableContent;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public RectTransform content { get { return m_Content; } set { m_Content = value; } }
- [SerializeField]
- private bool m_Horizontal = true;
- /// <summary>
- /// Should horizontal scrolling be enabled?
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- ///
- /// public void Start()
- /// {
- /// // Is horizontal scrolling enabled?
- /// if (myScrollRect.horizontal == true)
- /// {
- /// Debug.Log("Horizontal Scrolling is Enabled!");
- /// }
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public bool horizontal { get { return m_Horizontal; } set { m_Horizontal = value; } }
- [SerializeField]
- private bool m_Vertical = true;
- /// <summary>
- /// Should vertical scrolling be enabled?
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- ///
- /// public void Start()
- /// {
- /// // Is Vertical scrolling enabled?
- /// if (myScrollRect.vertical == true)
- /// {
- /// Debug.Log("Vertical Scrolling is Enabled!");
- /// }
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public bool vertical { get { return m_Vertical; } set { m_Vertical = value; } }
- [SerializeField]
- protected MovementType m_MovementType = MovementType.Elastic;
- /// <summary>
- /// The behavior to use when the content moves beyond the scroll rect.
- /// </summary>
- public MovementType movementType { get { return m_MovementType; } set { m_MovementType = value; } }
- [SerializeField]
- private float m_Elasticity = 0.1f;
- /// <summary>
- /// The amount of elasticity to use when the content moves beyond the scroll rect.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI;
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- ///
- /// public void Start()
- /// {
- /// // assigns a new value to the elasticity of the scroll rect.
- /// // The higher the number the longer it takes to snap back.
- /// myScrollRect.elasticity = 3.0f;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public float elasticity { get { return m_Elasticity; } set { m_Elasticity = value; } }
- [SerializeField]
- private bool m_Inertia = true;
- /// <summary>
- /// Should movement inertia be enabled?
- /// </summary>
- /// <remarks>
- /// Inertia means that the scrollrect content will keep scrolling for a while after being dragged. It gradually slows down according to the decelerationRate.
- /// </remarks>
- public bool inertia { get { return m_Inertia; } set { m_Inertia = value; } }
- [SerializeField]
- private float m_DecelerationRate = 0.135f; // Only used when inertia is enabled
- /// <summary>
- /// The rate at which movement slows down.
- /// </summary>
- /// <remarks>
- /// The deceleration rate is the speed reduction per second. A value of 0.5 halves the speed each second. The default is 0.135. The deceleration rate is only used when inertia is enabled.
- /// </remarks>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- ///
- /// public void Start()
- /// {
- /// // assigns a new value to the decelerationRate of the scroll rect.
- /// // The higher the number the longer it takes to decelerate.
- /// myScrollRect.decelerationRate = 5.0f;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public float decelerationRate { get { return m_DecelerationRate; } set { m_DecelerationRate = value; } }
- [SerializeField]
- private float m_ScrollSensitivity = 1.0f;
- /// <summary>
- /// The sensitivity to scroll wheel and track pad scroll events.
- /// </summary>
- /// <remarks>
- /// Higher values indicate higher sensitivity.
- /// </remarks>
- public float scrollSensitivity { get { return m_ScrollSensitivity; } set { m_ScrollSensitivity = value; } }
- [SerializeField]
- private RectTransform m_Viewport;
- /// <summary>
- /// Reference to the viewport RectTransform that is the parent of the content RectTransform.
- /// </summary>
- public RectTransform viewport { get { return m_Viewport; } set { m_Viewport = value; SetDirtyCaching(); } }
- [SerializeField]
- private Scrollbar m_HorizontalScrollbar;
- /// <summary>
- /// Optional Scrollbar object linked to the horizontal scrolling of the ScrollRect.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- /// public Scrollbar newScrollBar;
- ///
- /// public void Start()
- /// {
- /// // Assigns a scroll bar element to the ScrollRect, allowing you to scroll in the horizontal axis.
- /// myScrollRect.horizontalScrollbar = newScrollBar;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public Scrollbar horizontalScrollbar
- {
- get
- {
- return m_HorizontalScrollbar;
- }
- set
- {
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition);
- m_HorizontalScrollbar = value;
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition);
- SetDirtyCaching();
- }
- }
- [SerializeField]
- private Scrollbar m_VerticalScrollbar;
- /// <summary>
- /// Optional Scrollbar object linked to the vertical scrolling of the ScrollRect.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- /// public Scrollbar newScrollBar;
- ///
- /// public void Start()
- /// {
- /// // Assigns a scroll bar element to the ScrollRect, allowing you to scroll in the vertical axis.
- /// myScrollRect.verticalScrollbar = newScrollBar;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public Scrollbar verticalScrollbar
- {
- get
- {
- return m_VerticalScrollbar;
- }
- set
- {
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition);
- m_VerticalScrollbar = value;
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition);
- SetDirtyCaching();
- }
- }
- [SerializeField]
- private ScrollbarVisibility m_HorizontalScrollbarVisibility;
- /// <summary>
- /// The mode of visibility for the horizontal scrollbar.
- /// </summary>
- public ScrollbarVisibility horizontalScrollbarVisibility { get { return m_HorizontalScrollbarVisibility; } set { m_HorizontalScrollbarVisibility = value; SetDirtyCaching(); } }
- [SerializeField]
- private ScrollbarVisibility m_VerticalScrollbarVisibility;
- /// <summary>
- /// The mode of visibility for the vertical scrollbar.
- /// </summary>
- public ScrollbarVisibility verticalScrollbarVisibility { get { return m_VerticalScrollbarVisibility; } set { m_VerticalScrollbarVisibility = value; SetDirtyCaching(); } }
- [SerializeField]
- private float m_HorizontalScrollbarSpacing;
- /// <summary>
- /// The space between the scrollbar and the viewport.
- /// </summary>
- public float horizontalScrollbarSpacing { get { return m_HorizontalScrollbarSpacing; } set { m_HorizontalScrollbarSpacing = value; SetDirty(); } }
- [SerializeField]
- private float m_VerticalScrollbarSpacing;
- /// <summary>
- /// The space between the scrollbar and the viewport.
- /// </summary>
- public float verticalScrollbarSpacing { get { return m_VerticalScrollbarSpacing; } set { m_VerticalScrollbarSpacing = value; SetDirty(); } }
- [SerializeField]
- private ScrollRectEvent m_OnValueChanged = new ScrollRectEvent();
- /// <summary>
- /// Callback executed when the position of the child changes.
- /// </summary>
- /// <remarks>
- /// onValueChanged is used to watch for changes in the ScrollRect object.
- /// The onValueChanged call will use the UnityEvent.AddListener API to watch for
- /// changes. When changes happen script code provided by the user will be called.
- /// The UnityEvent.AddListener API for UI.ScrollRect._onValueChanged takes a Vector2.
- ///
- /// Note: The editor allows the onValueChanged value to be set up manually.For example the
- /// value can be set to run only a runtime. The object and script function to call are also
- /// provided here.
- ///
- /// The onValueChanged variable can be alternatively set-up at runtime.The script example below
- /// shows how this can be done.The script is attached to the ScrollRect object.
- /// </remarks>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using UnityEngine.UI;
- ///
- /// public class ExampleScript : MonoBehaviour
- /// {
- /// static ScrollRect scrollRect;
- ///
- /// void Start()
- /// {
- /// scrollRect = GetComponent<ScrollRect>();
- /// scrollRect.onValueChanged.AddListener(ListenerMethod);
- /// }
- ///
- /// public void ListenerMethod(Vector2 value)
- /// {
- /// Debug.Log("ListenerMethod: " + value);
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public ScrollRectEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
- // The offset from handle position to mouse down position
- protected Vector2 m_PointerStartLocalCursor = Vector2.zero;
- protected Vector2 m_ContentStartPosition = Vector2.zero;
- private RectTransform m_ViewRect;
- protected RectTransform viewRect
- {
- get
- {
- if (m_ViewRect == null)
- m_ViewRect = m_Viewport;
- if (m_ViewRect == null)
- m_ViewRect = (RectTransform)transform;
- return m_ViewRect;
- }
- }
- protected Bounds m_ContentBounds;
- protected Bounds m_ViewBounds;
- private Vector2 m_Velocity;
- /// <summary>
- /// The current velocity of the content.
- /// </summary>
- /// <remarks>
- /// The velocity is defined in units per second.
- /// </remarks>
- public Vector2 velocity { get { return m_Velocity; } set { m_Velocity = value; } }
- protected bool m_Dragging;
- private bool m_Scrolling;
- private Vector2 m_PrevPosition = Vector2.zero;
- private Bounds m_PrevContentBounds;
- private Bounds m_PrevViewBounds;
- [NonSerialized]
- private bool m_HasRebuiltLayout = false;
- private bool m_HSliderExpand;
- private bool m_VSliderExpand;
- private float m_HSliderHeight;
- private float m_VSliderWidth;
- [System.NonSerialized] private RectTransform m_Rect;
- private RectTransform rectTransform
- {
- get
- {
- if (m_Rect == null)
- m_Rect = GetComponent<RectTransform>();
- return m_Rect;
- }
- }
- private RectTransform m_HorizontalScrollbarRect;
- private RectTransform m_VerticalScrollbarRect;
- // field is never assigned warning
- #pragma warning disable 649
- private DrivenRectTransformTracker m_Tracker;
- #pragma warning restore 649
- protected UGUIScrollRect()
- { }
- /// <summary>
- /// Rebuilds the scroll rect data after initialization.
- /// </summary>
- /// <param name="executing">The current step in the rendering CanvasUpdate cycle.</param>
- public virtual void Rebuild(CanvasUpdate executing)
- {
- if (executing == CanvasUpdate.Prelayout)
- {
- UpdateCachedData();
- }
- if (executing == CanvasUpdate.PostLayout)
- {
- UpdateBounds();
- UpdateScrollbars(Vector2.zero);
- UpdatePrevData();
- m_HasRebuiltLayout = true;
- }
- }
- public virtual void LayoutComplete()
- { }
- public virtual void GraphicUpdateComplete()
- { }
- void UpdateCachedData()
- {
- Transform transform = this.transform;
- m_HorizontalScrollbarRect = m_HorizontalScrollbar == null ? null : m_HorizontalScrollbar.transform as RectTransform;
- m_VerticalScrollbarRect = m_VerticalScrollbar == null ? null : m_VerticalScrollbar.transform as RectTransform;
- // These are true if either the elements are children, or they don't exist at all.
- bool viewIsChild = (viewRect.parent == transform);
- bool hScrollbarIsChild = (!m_HorizontalScrollbarRect || m_HorizontalScrollbarRect.parent == transform);
- bool vScrollbarIsChild = (!m_VerticalScrollbarRect || m_VerticalScrollbarRect.parent == transform);
- bool allAreChildren = (viewIsChild && hScrollbarIsChild && vScrollbarIsChild);
- m_HSliderExpand = allAreChildren && m_HorizontalScrollbarRect && horizontalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport;
- m_VSliderExpand = allAreChildren && m_VerticalScrollbarRect && verticalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport;
- m_HSliderHeight = (m_HorizontalScrollbarRect == null ? 0 : m_HorizontalScrollbarRect.rect.height);
- m_VSliderWidth = (m_VerticalScrollbarRect == null ? 0 : m_VerticalScrollbarRect.rect.width);
- }
- protected override void OnEnable()
- {
- base.OnEnable();
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition);
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition);
- CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
- SetDirty();
- }
- protected override void OnDisable()
- {
- CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
- if (m_HorizontalScrollbar)
- m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition);
- if (m_VerticalScrollbar)
- m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition);
- m_Dragging = false;
- m_Scrolling = false;
- m_HasRebuiltLayout = false;
- m_Tracker.Clear();
- m_Velocity = Vector2.zero;
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
- base.OnDisable();
- }
- /// <summary>
- /// See member in base class.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- ///
- /// public void Start()
- /// {
- /// //Checks if the ScrollRect called "myScrollRect" is active.
- /// if (myScrollRect.IsActive())
- /// {
- /// Debug.Log("The Scroll Rect is active!");
- /// }
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public override bool IsActive()
- {
- return base.IsActive() && m_Content != null;
- }
- private void EnsureLayoutHasRebuilt()
- {
- if (!m_HasRebuiltLayout && !CanvasUpdateRegistry.IsRebuildingLayout())
- Canvas.ForceUpdateCanvases();
- }
- /// <summary>
- /// Sets the velocity to zero on both axes so the content stops moving.
- /// </summary>
- public virtual void StopMovement()
- {
- m_Velocity = Vector2.zero;
- }
- public virtual void OnScroll(PointerEventData data)
- {
- if (!IsActive())
- return;
- EnsureLayoutHasRebuilt();
- UpdateBounds();
- Vector2 delta = data.scrollDelta;
- // Down is positive for scroll events, while in UI system up is positive.
- delta.y *= -1;
- if (vertical && !horizontal)
- {
- if (Mathf.Abs(delta.x) > Mathf.Abs(delta.y))
- delta.y = delta.x;
- delta.x = 0;
- }
- if (horizontal && !vertical)
- {
- if (Mathf.Abs(delta.y) > Mathf.Abs(delta.x))
- delta.x = delta.y;
- delta.y = 0;
- }
- if (data.IsScrolling())
- m_Scrolling = true;
- Vector2 position = m_Content.anchoredPosition;
- position += delta * m_ScrollSensitivity;
- if (m_MovementType == MovementType.Clamped)
- position += CalculateOffset(position - m_Content.anchoredPosition);
- SetContentAnchoredPosition(position);
- UpdateBounds();
- }
- public virtual void OnInitializePotentialDrag(PointerEventData eventData)
- {
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- m_Velocity = Vector2.zero;
- }
- /// <summary>
- /// Handling for when the content is beging being dragged.
- /// </summary>
- ///<example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.EventSystems; // Required when using event data
- ///
- /// public class ExampleClass : MonoBehaviour, IBeginDragHandler // required interface when using the OnBeginDrag method.
- /// {
- /// //Do this when the user starts dragging the element this script is attached to..
- /// public void OnBeginDrag(PointerEventData data)
- /// {
- /// Debug.Log("They started dragging " + this.name);
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public virtual void OnBeginDrag(PointerEventData eventData)
- {
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- if (!IsActive())
- return;
- UpdateBounds();
- m_PointerStartLocalCursor = Vector2.zero;
- RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out m_PointerStartLocalCursor);
- m_ContentStartPosition = m_Content.anchoredPosition;
- m_Dragging = true;
- }
- /// <summary>
- /// Handling for when the content has finished being dragged.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.EventSystems; // Required when using event data
- ///
- /// public class ExampleClass : MonoBehaviour, IEndDragHandler // required interface when using the OnEndDrag method.
- /// {
- /// //Do this when the user stops dragging this UI Element.
- /// public void OnEndDrag(PointerEventData data)
- /// {
- /// Debug.Log("Stopped dragging " + this.name + "!");
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public virtual void OnEndDrag(PointerEventData eventData)
- {
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- m_Dragging = false;
- }
- /// <summary>
- /// Handling for when the content is dragged.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.EventSystems; // Required when using event data
- ///
- /// public class ExampleClass : MonoBehaviour, IDragHandler // required interface when using the OnDrag method.
- /// {
- /// //Do this while the user is dragging this UI Element.
- /// public void OnDrag(PointerEventData data)
- /// {
- /// Debug.Log("Currently dragging " + this.name);
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public virtual void OnDrag(PointerEventData eventData)
- {
- if (!m_Dragging)
- return;
- if (eventData.button != PointerEventData.InputButton.Left)
- return;
- if (!IsActive())
- return;
- Vector2 localCursor;
- if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out localCursor))
- return;
- RKLog.Debug($"====UGUIScrollRect====: {eventData.pressEventCamera.name},{eventData.position},{localCursor}");
- UpdateBounds();
- var pointerDelta = localCursor - m_PointerStartLocalCursor;
- Vector2 position = m_ContentStartPosition + pointerDelta;
- // Offset to get content into place in the view.
- Vector2 offset = CalculateOffset(position - m_Content.anchoredPosition);
- position += offset;
- if (m_MovementType == MovementType.Elastic)
- {
- if (offset.x != 0)
- position.x = position.x - RubberDelta(offset.x, m_ViewBounds.size.x);
- if (offset.y != 0)
- position.y = position.y - RubberDelta(offset.y, m_ViewBounds.size.y);
- }
- SetContentAnchoredPosition(position);
- }
- /// <summary>
- /// Sets the anchored position of the content.
- /// </summary>
- protected virtual void SetContentAnchoredPosition(Vector2 position)
- {
- if (!m_Horizontal)
- position.x = m_Content.anchoredPosition.x;
- if (!m_Vertical)
- position.y = m_Content.anchoredPosition.y;
- if (position != m_Content.anchoredPosition)
- {
- m_Content.anchoredPosition = position;
- UpdateBounds();
- }
- }
- protected virtual void LateUpdate()
- {
- if (!m_Content)
- return;
- EnsureLayoutHasRebuilt();
- UpdateBounds();
- float deltaTime = Time.unscaledDeltaTime;
- Vector2 offset = CalculateOffset(Vector2.zero);
- if (deltaTime > 0.0f)
- {
- if (!m_Dragging && (offset != Vector2.zero || m_Velocity != Vector2.zero))
- {
- Vector2 position = m_Content.anchoredPosition;
- for (int axis = 0; axis < 2; axis++)
- {
- // Apply spring physics if movement is elastic and content has an offset from the view.
- if (m_MovementType == MovementType.Elastic && offset[axis] != 0)
- {
- float speed = m_Velocity[axis];
- float smoothTime = m_Elasticity;
- if (m_Scrolling)
- smoothTime *= 3.0f;
- position[axis] = Mathf.SmoothDamp(m_Content.anchoredPosition[axis], m_Content.anchoredPosition[axis] + offset[axis], ref speed, smoothTime, Mathf.Infinity, deltaTime);
- if (Mathf.Abs(speed) < 1)
- speed = 0;
- m_Velocity[axis] = speed;
- }
- // Else move content according to velocity with deceleration applied.
- else if (m_Inertia)
- {
- m_Velocity[axis] *= Mathf.Pow(m_DecelerationRate, deltaTime);
- if (Mathf.Abs(m_Velocity[axis]) < 1)
- m_Velocity[axis] = 0;
- position[axis] += m_Velocity[axis] * deltaTime;
- }
- // If we have neither elaticity or friction, there shouldn't be any velocity.
- else
- {
- m_Velocity[axis] = 0;
- }
- }
- if (m_MovementType == MovementType.Clamped)
- {
- offset = CalculateOffset(position - m_Content.anchoredPosition);
- position += offset;
- }
- SetContentAnchoredPosition(position);
- }
- if (m_Dragging && m_Inertia)
- {
- Vector3 newVelocity = (m_Content.anchoredPosition - m_PrevPosition) / deltaTime;
- m_Velocity = Vector3.Lerp(m_Velocity, newVelocity, deltaTime * 10);
- }
- }
- if (m_ViewBounds != m_PrevViewBounds || m_ContentBounds != m_PrevContentBounds || m_Content.anchoredPosition != m_PrevPosition)
- {
- UpdateScrollbars(offset);
- UISystemProfilerApi.AddMarker("ScrollRect.value", this);
- m_OnValueChanged.Invoke(normalizedPosition);
- UpdatePrevData();
- }
- UpdateScrollbarVisibility();
- m_Scrolling = false;
- }
- /// <summary>
- /// Helper function to update the previous data fields on a ScrollRect. Call this before you change data in the ScrollRect.
- /// </summary>
- protected void UpdatePrevData()
- {
- if (m_Content == null)
- m_PrevPosition = Vector2.zero;
- else
- m_PrevPosition = m_Content.anchoredPosition;
- m_PrevViewBounds = m_ViewBounds;
- m_PrevContentBounds = m_ContentBounds;
- }
- private void UpdateScrollbars(Vector2 offset)
- {
- if (m_HorizontalScrollbar)
- {
- if (m_ContentBounds.size.x > 0)
- m_HorizontalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.x - Mathf.Abs(offset.x)) / m_ContentBounds.size.x);
- else
- m_HorizontalScrollbar.size = 1;
- m_HorizontalScrollbar.value = horizontalNormalizedPosition;
- }
- if (m_VerticalScrollbar)
- {
- if (m_ContentBounds.size.y > 0)
- m_VerticalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.y - Mathf.Abs(offset.y)) / m_ContentBounds.size.y);
- else
- m_VerticalScrollbar.size = 1;
- m_VerticalScrollbar.value = verticalNormalizedPosition;
- }
- }
- /// <summary>
- /// The scroll position as a Vector2 between (0,0) and (1,1) with (0,0) being the lower left corner.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- /// public Vector2 myPosition = new Vector2(0.5f, 0.5f);
- ///
- /// public void Start()
- /// {
- /// //Change the current scroll position.
- /// myScrollRect.normalizedPosition = myPosition;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public Vector2 normalizedPosition
- {
- get
- {
- return new Vector2(horizontalNormalizedPosition, verticalNormalizedPosition);
- }
- set
- {
- SetNormalizedPosition(value.x, 0);
- SetNormalizedPosition(value.y, 1);
- }
- }
- /// <summary>
- /// The horizontal scroll position as a value between 0 and 1, with 0 being at the left.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- /// public Scrollbar newScrollBar;
- ///
- /// public void Start()
- /// {
- /// //Change the current horizontal scroll position.
- /// myScrollRect.horizontalNormalizedPosition = 0.5f;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public float horizontalNormalizedPosition
- {
- get
- {
- UpdateBounds();
- if ((m_ContentBounds.size.x <= m_ViewBounds.size.x) || Mathf.Approximately(m_ContentBounds.size.x, m_ViewBounds.size.x))
- return (m_ViewBounds.min.x > m_ContentBounds.min.x) ? 1 : 0;
- return (m_ViewBounds.min.x - m_ContentBounds.min.x) / (m_ContentBounds.size.x - m_ViewBounds.size.x);
- }
- set
- {
- SetNormalizedPosition(value, 0);
- }
- }
- /// <summary>
- /// The vertical scroll position as a value between 0 and 1, with 0 being at the bottom.
- /// </summary>
- /// <example>
- /// <code>
- /// <![CDATA[
- /// using UnityEngine;
- /// using System.Collections;
- /// using UnityEngine.UI; // Required when Using UI elements.
- ///
- /// public class ExampleClass : MonoBehaviour
- /// {
- /// public ScrollRect myScrollRect;
- /// public Scrollbar newScrollBar;
- ///
- /// public void Start()
- /// {
- /// //Change the current vertical scroll position.
- /// myScrollRect.verticalNormalizedPosition = 0.5f;
- /// }
- /// }
- /// ]]>
- ///</code>
- /// </example>
- public float verticalNormalizedPosition
- {
- get
- {
- UpdateBounds();
- if ((m_ContentBounds.size.y <= m_ViewBounds.size.y) || Mathf.Approximately(m_ContentBounds.size.y, m_ViewBounds.size.y))
- return (m_ViewBounds.min.y > m_ContentBounds.min.y) ? 1 : 0;
- return (m_ViewBounds.min.y - m_ContentBounds.min.y) / (m_ContentBounds.size.y - m_ViewBounds.size.y);
- }
- set
- {
- SetNormalizedPosition(value, 1);
- }
- }
- private void SetHorizontalNormalizedPosition(float value) { SetNormalizedPosition(value, 0); }
- private void SetVerticalNormalizedPosition(float value) { SetNormalizedPosition(value, 1); }
- /// <summary>
- /// >Set the horizontal or vertical scroll position as a value between 0 and 1, with 0 being at the left or at the bottom.
- /// </summary>
- /// <param name="value">The position to set, between 0 and 1.</param>
- /// <param name="axis">The axis to set: 0 for horizontal, 1 for vertical.</param>
- protected virtual void SetNormalizedPosition(float value, int axis)
- {
- EnsureLayoutHasRebuilt();
- UpdateBounds();
- // How much the content is larger than the view.
- float hiddenLength = m_ContentBounds.size[axis] - m_ViewBounds.size[axis];
- // Where the position of the lower left corner of the content bounds should be, in the space of the view.
- float contentBoundsMinPosition = m_ViewBounds.min[axis] - value * hiddenLength;
- // The new content localPosition, in the space of the view.
- float newAnchoredPosition = m_Content.anchoredPosition[axis] + contentBoundsMinPosition - m_ContentBounds.min[axis];
- Vector3 anchoredPosition = m_Content.anchoredPosition;
- if (Mathf.Abs(anchoredPosition[axis] - newAnchoredPosition) > 0.01f)
- {
- anchoredPosition[axis] = newAnchoredPosition;
- m_Content.anchoredPosition = anchoredPosition;
- m_Velocity[axis] = 0;
- UpdateBounds();
- }
- }
- protected static float RubberDelta(float overStretching, float viewSize)
- {
- return (1 - (1 / ((Mathf.Abs(overStretching) * 0.55f / viewSize) + 1))) * viewSize * Mathf.Sign(overStretching);
- }
- protected override void OnRectTransformDimensionsChange()
- {
- SetDirty();
- }
- private bool hScrollingNeeded
- {
- get
- {
- if (Application.isPlaying)
- return m_ContentBounds.size.x > m_ViewBounds.size.x + 0.01f;
- return true;
- }
- }
- private bool vScrollingNeeded
- {
- get
- {
- if (Application.isPlaying)
- return m_ContentBounds.size.y > m_ViewBounds.size.y + 0.01f;
- return true;
- }
- }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual void CalculateLayoutInputHorizontal() { }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual void CalculateLayoutInputVertical() { }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual float minWidth { get { return -1; } }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual float preferredWidth { get { return -1; } }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual float flexibleWidth { get { return -1; } }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual float minHeight { get { return -1; } }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual float preferredHeight { get { return -1; } }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual float flexibleHeight { get { return -1; } }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual int layoutPriority { get { return -1; } }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual void SetLayoutHorizontal()
- {
- m_Tracker.Clear();
- UpdateCachedData();
- if (m_HSliderExpand || m_VSliderExpand)
- {
- m_Tracker.Add(this, viewRect,
- DrivenTransformProperties.Anchors |
- DrivenTransformProperties.SizeDelta |
- DrivenTransformProperties.AnchoredPosition);
- // Make view full size to see if content fits.
- viewRect.anchorMin = Vector2.zero;
- viewRect.anchorMax = Vector2.one;
- viewRect.sizeDelta = Vector2.zero;
- viewRect.anchoredPosition = Vector2.zero;
- // Recalculate content layout with this size to see if it fits when there are no scrollbars.
- LayoutRebuilder.ForceRebuildLayoutImmediate(content);
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it.
- if (m_VSliderExpand && vScrollingNeeded)
- {
- viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y);
- // Recalculate content layout with this size to see if it fits vertically
- // when there is a vertical scrollbar (which may reflowed the content to make it taller).
- LayoutRebuilder.ForceRebuildLayoutImmediate(content);
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- // If it doesn't fit horizontally, enable horizontal scrollbar and shrink view vertically to make room for it.
- if (m_HSliderExpand && hScrollingNeeded)
- {
- viewRect.sizeDelta = new Vector2(viewRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing));
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- // If the vertical slider didn't kick in the first time, and the horizontal one did,
- // we need to check again if the vertical slider now needs to kick in.
- // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it.
- if (m_VSliderExpand && vScrollingNeeded && viewRect.sizeDelta.x == 0 && viewRect.sizeDelta.y < 0)
- {
- viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y);
- }
- }
- /// <summary>
- /// Called by the layout system.
- /// </summary>
- public virtual void SetLayoutVertical()
- {
- UpdateScrollbarLayout();
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- }
- void UpdateScrollbarVisibility()
- {
- UpdateOneScrollbarVisibility(vScrollingNeeded, m_Vertical, m_VerticalScrollbarVisibility, m_VerticalScrollbar);
- UpdateOneScrollbarVisibility(hScrollingNeeded, m_Horizontal, m_HorizontalScrollbarVisibility, m_HorizontalScrollbar);
- }
- private static void UpdateOneScrollbarVisibility(bool xScrollingNeeded, bool xAxisEnabled, ScrollbarVisibility scrollbarVisibility, Scrollbar scrollbar)
- {
- if (scrollbar)
- {
- if (scrollbarVisibility == ScrollbarVisibility.Permanent)
- {
- if (scrollbar.gameObject.activeSelf != xAxisEnabled)
- scrollbar.gameObject.SetActive(xAxisEnabled);
- }
- else
- {
- if (scrollbar.gameObject.activeSelf != xScrollingNeeded)
- scrollbar.gameObject.SetActive(xScrollingNeeded);
- }
- }
- }
- void UpdateScrollbarLayout()
- {
- if (m_VSliderExpand && m_HorizontalScrollbar)
- {
- m_Tracker.Add(this, m_HorizontalScrollbarRect,
- DrivenTransformProperties.AnchorMinX |
- DrivenTransformProperties.AnchorMaxX |
- DrivenTransformProperties.SizeDeltaX |
- DrivenTransformProperties.AnchoredPositionX);
- m_HorizontalScrollbarRect.anchorMin = new Vector2(0, m_HorizontalScrollbarRect.anchorMin.y);
- m_HorizontalScrollbarRect.anchorMax = new Vector2(1, m_HorizontalScrollbarRect.anchorMax.y);
- m_HorizontalScrollbarRect.anchoredPosition = new Vector2(0, m_HorizontalScrollbarRect.anchoredPosition.y);
- if (vScrollingNeeded)
- m_HorizontalScrollbarRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), m_HorizontalScrollbarRect.sizeDelta.y);
- else
- m_HorizontalScrollbarRect.sizeDelta = new Vector2(0, m_HorizontalScrollbarRect.sizeDelta.y);
- }
- if (m_HSliderExpand && m_VerticalScrollbar)
- {
- m_Tracker.Add(this, m_VerticalScrollbarRect,
- DrivenTransformProperties.AnchorMinY |
- DrivenTransformProperties.AnchorMaxY |
- DrivenTransformProperties.SizeDeltaY |
- DrivenTransformProperties.AnchoredPositionY);
- m_VerticalScrollbarRect.anchorMin = new Vector2(m_VerticalScrollbarRect.anchorMin.x, 0);
- m_VerticalScrollbarRect.anchorMax = new Vector2(m_VerticalScrollbarRect.anchorMax.x, 1);
- m_VerticalScrollbarRect.anchoredPosition = new Vector2(m_VerticalScrollbarRect.anchoredPosition.x, 0);
- if (hScrollingNeeded)
- m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing));
- else
- m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, 0);
- }
- }
- /// <summary>
- /// Calculate the bounds the ScrollRect should be using.
- /// </summary>
- protected void UpdateBounds()
- {
- m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
- m_ContentBounds = GetBounds();
- if (m_Content == null)
- return;
- Vector3 contentSize = m_ContentBounds.size;
- Vector3 contentPos = m_ContentBounds.center;
- var contentPivot = m_Content.pivot;
- AdjustBounds(ref m_ViewBounds, ref contentPivot, ref contentSize, ref contentPos);
- m_ContentBounds.size = contentSize;
- m_ContentBounds.center = contentPos;
- if (movementType == MovementType.Clamped)
- {
- // Adjust content so that content bounds bottom (right side) is never higher (to the left) than the view bounds bottom (right side).
- // top (left side) is never lower (to the right) than the view bounds top (left side).
- // All this can happen if content has shrunk.
- // This works because content size is at least as big as view size (because of the call to InternalUpdateBounds above).
- Vector2 delta = Vector2.zero;
- if (m_ViewBounds.max.x > m_ContentBounds.max.x)
- {
- delta.x = Math.Min(m_ViewBounds.min.x - m_ContentBounds.min.x, m_ViewBounds.max.x - m_ContentBounds.max.x);
- }
- else if (m_ViewBounds.min.x < m_ContentBounds.min.x)
- {
- delta.x = Math.Max(m_ViewBounds.min.x - m_ContentBounds.min.x, m_ViewBounds.max.x - m_ContentBounds.max.x);
- }
- if (m_ViewBounds.min.y < m_ContentBounds.min.y)
- {
- delta.y = Math.Max(m_ViewBounds.min.y - m_ContentBounds.min.y, m_ViewBounds.max.y - m_ContentBounds.max.y);
- }
- else if (m_ViewBounds.max.y > m_ContentBounds.max.y)
- {
- delta.y = Math.Min(m_ViewBounds.min.y - m_ContentBounds.min.y, m_ViewBounds.max.y - m_ContentBounds.max.y);
- }
- if (delta.sqrMagnitude > float.Epsilon)
- {
- contentPos = m_Content.anchoredPosition + delta;
- if (!m_Horizontal)
- contentPos.x = m_Content.anchoredPosition.x;
- if (!m_Vertical)
- contentPos.y = m_Content.anchoredPosition.y;
- AdjustBounds(ref m_ViewBounds, ref contentPivot, ref contentSize, ref contentPos);
- }
- }
- }
- internal static void AdjustBounds(ref Bounds viewBounds, ref Vector2 contentPivot, ref Vector3 contentSize, ref Vector3 contentPos)
- {
- // Make sure content bounds are at least as large as view by adding padding if not.
- // One might think at first that if the content is smaller than the view, scrolling should be allowed.
- // However, that's not how scroll views normally work.
- // Scrolling is *only* possible when content is *larger* than view.
- // We use the pivot of the content rect to decide in which directions the content bounds should be expanded.
- // E.g. if pivot is at top, bounds are expanded downwards.
- // This also works nicely when ContentSizeFitter is used on the content.
- Vector3 excess = viewBounds.size - contentSize;
- if (excess.x > 0)
- {
- contentPos.x -= excess.x * (contentPivot.x - 0.5f);
- contentSize.x = viewBounds.size.x;
- }
- if (excess.y > 0)
- {
- contentPos.y -= excess.y * (contentPivot.y - 0.5f);
- contentSize.y = viewBounds.size.y;
- }
- }
- private readonly Vector3[] m_Corners = new Vector3[4];
- private Bounds GetBounds()
- {
- if (m_Content == null)
- return new Bounds();
- m_Content.GetWorldCorners(m_Corners);
- var viewWorldToLocalMatrix = viewRect.worldToLocalMatrix;
- return InternalGetBounds(m_Corners, ref viewWorldToLocalMatrix);
- }
- internal static Bounds InternalGetBounds(Vector3[] corners, ref Matrix4x4 viewWorldToLocalMatrix)
- {
- var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
- var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
- for (int j = 0; j < 4; j++)
- {
- Vector3 v = viewWorldToLocalMatrix.MultiplyPoint3x4(corners[j]);
- vMin = Vector3.Min(v, vMin);
- vMax = Vector3.Max(v, vMax);
- }
- var bounds = new Bounds(vMin, Vector3.zero);
- bounds.Encapsulate(vMax);
- return bounds;
- }
- protected Vector2 CalculateOffset(Vector2 delta)
- {
- return InternalCalculateOffset(ref m_ViewBounds, ref m_ContentBounds, m_Horizontal, m_Vertical, m_MovementType, ref delta);
- }
- internal static Vector2 InternalCalculateOffset(ref Bounds viewBounds, ref Bounds contentBounds, bool horizontal, bool vertical, MovementType movementType, ref Vector2 delta)
- {
- Vector2 offset = Vector2.zero;
- if (movementType == MovementType.Unrestricted)
- return offset;
- Vector2 min = contentBounds.min;
- Vector2 max = contentBounds.max;
- // min/max offset extracted to check if approximately 0 and avoid recalculating layout every frame (case 1010178)
- if (horizontal)
- {
- min.x += delta.x;
- max.x += delta.x;
- float maxOffset = viewBounds.max.x - max.x;
- float minOffset = viewBounds.min.x - min.x;
- if (minOffset < -0.001f)
- offset.x = minOffset;
- else if (maxOffset > 0.001f)
- offset.x = maxOffset;
- }
- if (vertical)
- {
- min.y += delta.y;
- max.y += delta.y;
- float maxOffset = viewBounds.max.y - max.y;
- float minOffset = viewBounds.min.y - min.y;
- if (maxOffset > 0.001f)
- offset.y = maxOffset;
- else if (minOffset < -0.001f)
- offset.y = minOffset;
- }
- return offset;
- }
- /// <summary>
- /// Override to alter or add to the code that keeps the appearance of the scroll rect synced with its data.
- /// </summary>
- protected void SetDirty()
- {
- if (!IsActive())
- return;
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
- }
- /// <summary>
- /// Override to alter or add to the code that caches data to avoid repeated heavy operations.
- /// </summary>
- protected void SetDirtyCaching()
- {
- if (!IsActive())
- return;
- CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
- LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
- m_ViewRect = null;
- }
- #if UNITY_EDITOR
- protected override void OnValidate()
- {
- SetDirtyCaching();
- }
- #endif
- }
- }
|