/// Credit Beka Westberg /// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/28 /// Updated by SimonDarksideJ - Added some exception management and a SetNewItems to replace the content programmatically using System.Collections; using System.Collections.Generic; using UnityEngine.EventSystems; using UnityEngine.Events; using System; namespace UnityEngine.UI.Extensions { [ExecuteInEditMode] [RequireComponent(typeof(ScrollRect))] [AddComponentMenu("UI/Extensions/ContentSnapScrollHorizontal")] public class ContentScrollSnapHorizontal : MonoBehaviour, IBeginDragHandler, IEndDragHandler { [Serializable] public class StartMovementEvent : UnityEvent { } [Serializable] public class CurrentItemChangeEvent : UnityEvent { } [Serializable] public class FoundItemToSnapToEvent : UnityEvent { } [Serializable] public class SnappedToItemEvent : UnityEvent { } public bool ignoreInactiveItems = true; public MoveInfo startInfo = new MoveInfo(MoveInfo.IndexType.positionIndex, 0); public GameObject prevButton; public GameObject nextButton; public GameObject pagination; [Tooltip("The velocity below which the scroll rect will start to snap")] public int snappingVelocityThreshold = 50; [Header("Paging Info")] [Tooltip("Should the pagination & buttons jump or lerp to the items")] public bool jumpToItem = false; [Tooltip("The time it will take for the pagination or buttons to move between items")] public float lerpTime = .3f; [Header("Events")] [SerializeField] [Tooltip("Event is triggered whenever the scroll rect starts to move, even when triggered programmatically")] private StartMovementEvent m_StartMovementEvent = new StartMovementEvent(); public StartMovementEvent MovementStarted { get { return m_StartMovementEvent; } set { m_StartMovementEvent = value; } } [SerializeField] [Tooltip("Event is triggered whenever the closest item to the center of the scrollrect changes")] private CurrentItemChangeEvent m_CurrentItemChangeEvent = new CurrentItemChangeEvent(); public CurrentItemChangeEvent CurrentItemChanged { get { return m_CurrentItemChangeEvent; } set { m_CurrentItemChangeEvent = value; } } [SerializeField] [Tooltip("Event is triggered when the ContentSnapScroll decides which item it is going to snap to. Returns the index of the closest position.")] private FoundItemToSnapToEvent m_FoundItemToSnapToEvent = new FoundItemToSnapToEvent(); public FoundItemToSnapToEvent ItemFoundToSnap { get { return m_FoundItemToSnapToEvent; } set { m_FoundItemToSnapToEvent = value; } } [SerializeField] [Tooltip("Event is triggered when we finally settle on an element. Returns the index of the item's position.")] private SnappedToItemEvent m_SnappedToItemEvent = new SnappedToItemEvent(); public SnappedToItemEvent ItemSnappedTo { get { return m_SnappedToItemEvent; } set { m_SnappedToItemEvent = value; } } private ScrollRect scrollRect = null; private RectTransform scrollRectTransform = null; private RectTransform contentTransform = null; private List contentPositions = null; private Vector3 lerpTarget = Vector3.zero; private float totalScrollableWidth = 0; private DrivenRectTransformTracker tracker ; private float mLerpTime = 0; private int _closestItem = 0; private bool mSliding = false; private bool mLerping = false; private bool ContentIsHorizonalLayoutGroup { get { return contentTransform.GetComponent() != null; } } #region Public Info /// /// Returns if the SnapScroll is moving /// public bool Moving { get { return Sliding || Lerping; } } /// /// Returns if the SnapScroll is moving because of a touch /// public bool Sliding { get { return mSliding; } } /// /// Returns if the SnapScroll is moving programmatically /// public bool Lerping { get { return mLerping; } } /// /// Returns the closest item's index /// *Note this is zero based, and based on position not child order /// public int ClosestItemIndex { get { return contentPositions.IndexOf(FindClosestFrom(contentTransform.localPosition)); } } /// /// Returns the lerpTarget's index /// *Note this is zero-based, and based on position not child order /// public int LerpTargetIndex { get { return contentPositions.IndexOf(lerpTarget); } } #endregion #region Setup private void Awake() { scrollRect = GetComponent(); scrollRectTransform = (RectTransform) scrollRect.transform; contentTransform = scrollRect.content; if (nextButton) nextButton.GetComponent