#region Includes using UnityEngine; using UnityEngine.Events; using System.Collections.Generic; using System.Collections; #endregion #if UNITY_EDITOR using UnityEditor; #endif /// /// The PageSlider class manages a collection of pages within a PageScroller component. /// It provides functionality for adding, removing, and keeping track of pages, /// as well as handling page change events. /// public class PageSlider : MonoBehaviour { #region Variables [Header("References")] /// /// "An optional reference to a PageDotsIndicator component used to display dots for each page." /// [Tooltip("Optional reference to a PageDotsIndicator to display dots for each page")] [SerializeField] private PageDotsIndicator _dotsIndicator; [Header("Children")] /// /// A list of PageContainer components representing the pages managed by the PageSlider. /// [Tooltip("A list of PageContainer components representing the pages managed by the PageSlider")] [SerializeField] private List _pages; [Header("Configuration")] /// /// The index of the page to show at start. /// [Tooltip("The index of the page to show at start")] [SerializeField] private int _startPageIndex; [Header("Events")] /// /// Invoked whenever the active page changes. /// The event argument is a reference to the new active page. /// public UnityEvent OnPageChanged; /// /// Gets the rectangle of the PageSlider component. /// public Rect Rect { get { return ((RectTransform)transform).rect; } } private PageScroller _scroller; #endregion private void Awake() { _scroller = FindScroller(); } private IEnumerator Start() { _scroller.OnPageChangeStarted.AddListener(PageScroller_PageChangeStarted); _scroller.OnPageChangeEnded.AddListener(PageScroller_PageChangeEnded); yield return new WaitForEndOfFrame(); if (_startPageIndex == 0) yield break; _scroller.SetPage(_startPageIndex); } /// /// Adds a new page to the PageSlider. /// The content argument specifies the RectTransform of the content to be displayed on the new page. /// /// The RectTransform of the content to be displayed on the new page. public void AddPage(RectTransform content) { if (_scroller == null) { _scroller = FindScroller(); } // Initialize the pages list if it's null (first page). _pages ??= new List(); // Create a new GameObject for the page with a descriptive name. // Set the page's parent to the scroller's content transform. var page = new GameObject(string.Format("Page_{0}", _pages.Count), typeof(RectTransform), typeof(PageContainer)); page.transform.SetParent(_scroller.Content); // Get the RectTransform component of the newly created page. // Set the size of the page's RectTransform to match the size of the scroller's viewport. // Set the page's local scale to one (no scaling). var rectTransform = page.GetComponent(); rectTransform.sizeDelta = _scroller.Rect.size; rectTransform.localScale = Vector3.one; // Get the PageContainer component from the page GameObject. // Assign the provided content (RectTransform) to the PageContainer. var pageView = page.GetComponent(); pageView.AssignContent(content); // If this is the first page, trigger its activation state change. if (_pages.Count == 0) { pageView.ChangingToActiveState(); pageView.ChangeActiveState(true); } // Add the newly created page container to the internal list. _pages.Add(pageView); // If a dots indicator is assigned, add a new dot and update its visibility based on the number of pages. if (_dotsIndicator != null) { _dotsIndicator.Add(); _dotsIndicator.IsVisible = _pages.Count > 1; } #if UNITY_EDITOR // In editor mode, mark the scene as dirty to save changes. if (Application.isPlaying) { return; } EditorUtility.SetDirty(this); #endif } /// /// Removes all pages from the PageSlider and clears the associated PageDotsIndicator (if exists). /// public void Clear() { for (int i = 0; i < _pages.Count; i++) { if (_pages[i] == null) { continue; } #if UNITY_EDITOR DestroyImmediate(_pages[i].gameObject); #else Destroy(_pages[i].gameObject); #endif } _pages.Clear(); if (_dotsIndicator != null) { _dotsIndicator.Clear(); } } /// /// Called by the PageScroller component when a page change starts. /// Deactivates the page at the fromIndex and activates the page at the toIndex. /// /// The index of the page that is being deactivated. /// The index of the page that is being activated. private void PageScroller_PageChangeStarted(int fromIndex, int toIndex) { _pages[fromIndex].ChangingToInactiveState(); _pages[toIndex].ChangingToActiveState(); } /// /// Called by the PageScroller component when a page change ends. Sets the page at the fromIndex to inactive and the page at the toIndex to active. Updates the PageDotsIndicator and invokes the OnPageChanged event. /// /// The index of the page that is being deactivated. /// The index of the page that is being activated. private void PageScroller_PageChangeEnded(int fromIndex, int toIndex) { _pages[fromIndex].ChangeActiveState(false); _pages[toIndex].ChangeActiveState(true); if (_dotsIndicator != null) { _dotsIndicator.ChangeActiveDot(fromIndex, toIndex); } OnPageChanged?.Invoke(_pages[toIndex]); } /// /// Finds the PageScroller component within the children of the gameobject this script is attached to. /// /// The PageScroller component found in the children, or null if not found. private PageScroller FindScroller() { var scroller = GetComponentInChildren(); #if UNITY_EDITOR || DEVELOPMENT_BUILD if (scroller == null) { Debug.LogError("Missing PageScroller in Children"); } #endif return scroller; } #if UNITY_EDITOR [CustomEditor(typeof(PageSlider))] public class PageControllerEditor : Editor { #region Variables private PageSlider _target; private RectTransform _contentPrefab; #endregion private void OnEnable() { _target = (PageSlider)target; } public override void OnInspectorGUI() { base.OnInspectorGUI(); EditorGUILayout.Space(); EditorGUILayout.LabelField("Editor"); _contentPrefab = (RectTransform)EditorGUILayout.ObjectField(_contentPrefab, typeof(RectTransform), false); if (GUILayout.Button("Add Page")) { _target.AddPage((RectTransform)PrefabUtility.InstantiatePrefab(_contentPrefab)); } if (GUILayout.Button("Clear")) { _target.Clear(); } } } #endif }