diff --git a/Runtime/FlipPage/FlipPageComponentManager.cs b/Runtime/FlipPage/FlipPageComponentManager.cs index e79b342..0a05bfd 100644 --- a/Runtime/FlipPage/FlipPageComponentManager.cs +++ b/Runtime/FlipPage/FlipPageComponentManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -44,7 +45,7 @@ namespace XericUI.FlipPage [Tooltip("候选页按最多数é‡�展示")] [SerializeField] protected bool inMaximumCandidatesNumber = false; - + /// /// 首页按钮 /// @@ -81,12 +82,11 @@ namespace XericUI.FlipPage /// 总页é�¢æ•°é‡�文本 /// #if ODIN_INSPECTOR - [Space(2)] - [LabelText("总页é�¢æ•°é‡�文本")] [BoxGroup("组件")] + [Space(2)] [LabelText("总页é�¢æ•°é‡�文本")] [BoxGroup("组件")] #endif public ObjectVessel labelTextTotalPageCount = new ObjectVessel(); - + /// /// 总页é�¢æ•°é‡�文本格å¼�化 /// @@ -94,7 +94,7 @@ namespace XericUI.FlipPage [LabelText("总页é�¢æ•°é‡�文本格å¼�化")] [BoxGroup("设定")] #endif public string totalPageCountFormat = "å…±$1页"; - + /// /// 页é�¢ç´¢å¼•文本格å¼�化 /// @@ -107,7 +107,8 @@ namespace XericUI.FlipPage /// 页é�¢é€‰æ‹©ç»„件列表 /// #if ODIN_INSPECTOR - [LabelText("页é�¢é€‰æ‹©ç»„件列表")] [BoxGroup("组件")] + [LabelText("页é�¢é€‰æ‹©ç»„件列表")] + [BoxGroup("组件")] // [ListDrawerSettings(ShowIndexLabels = true)] #endif [Tooltip("首个组件应当作为主è¦�的节点管ç�†")] @@ -128,13 +129,13 @@ namespace XericUI.FlipPage #if ODIN_INSPECTOR [LabelText("翻页到索引按钮池")] [BoxGroup("组件")] #endif - public XericLibrary.Runtime.MacroLibrary.MacroPool.UnionSet pageButtonPool = new XericLibrary.Runtime.MacroLibrary.MacroPool.UnionSet(); + public XericLibrary.Runtime.MacroLibrary.MacroPool.UnionSet pageButtonPool = + new XericLibrary.Runtime.MacroLibrary.MacroPool.UnionSet(); #endregion #region 字段属性 - private ToggleGroup _toggleGroup; protected ToggleGroup ToggleGroup @@ -149,7 +150,7 @@ namespace XericUI.FlipPage } #endregion - + #region 类内类型 /// @@ -161,23 +162,20 @@ namespace XericUI.FlipPage /// 页é�¢ç¿»é¡µæŒ‰é’® /// #if ODIN_INSPECTOR - [LabelText("页é�¢ç¿»é¡µæŒ‰é’®")] + [LabelText("页é�¢ç¿»é¡µæŒ‰é’®")] #endif [CanBeNull] internal ObjectVessel pageSelectableVessel; - - - + + protected internal override void OnPageVisible(bool quickVisit) { - if (quickVisit) - return; + if (quickVisit) return; // 自动补全外部交互动画 if (pageSelectableVessel.IsValidVessel()) SwitchSelectableVesselType(pageSelectableVessel.Target0, - null, - toggle => + asToggle: toggle => { if (!toggle.isOn) toggle.SetIsOnWithoutNotify(true); @@ -186,8 +184,8 @@ namespace XericUI.FlipPage protected internal override void OnPageInvisible(bool quickVisit) { + } - } /// @@ -205,7 +203,7 @@ namespace XericUI.FlipPage } #endregion - + #region 生命周期 #if UNITY_EDITOR @@ -215,10 +213,14 @@ namespace XericUI.FlipPage // pageButtonPool.Prefab.GetComponent(); } #endif - + protected override void Awake() { + // 使用默认的 + HowToCreatPageInfo = () => AddPage(new PageComponentInfo()); + base.Awake(); + if (buttonStartPage.IsValidVessel()) // 翻到开头 buttonStartPage.Target.onClick.AddListener(FlipPageToStart); if (buttonPreviousPage.IsValidVessel()) // 翻到上一页 @@ -230,10 +232,9 @@ namespace XericUI.FlipPage if (inputFieldFlipPageIndex.IsValidVessel()) // 翻到指定 inputFieldFlipPageIndex.Target.onValueChanged.AddListener(s => FlipPage(s)); pageButtonPool.Init(); - + // æ ¹æ�®ç»„件类型创建相关内容 // var prefabSelectable = pageButtonPool.Prefab.GetComponent(); - } #endregion @@ -250,12 +251,11 @@ namespace XericUI.FlipPage pageSelectButton[i].Target0.transform.SetSiblingIndex(i); } - if (Currentpage is PageComponentInfo componentPage && + if (Currentpage is PageComponentInfo componentPage && componentPage.pageSelectableVessel.IsValidVessel()) { SwitchSelectableVesselType(componentPage.pageSelectableVessel.Target0, - null, - toggle => + asToggle: toggle => { if (!toggle.isOn) toggle.isOn = true; @@ -266,19 +266,22 @@ namespace XericUI.FlipPage public override void FlipPage(int pageIndex, bool forceRefresh = false) { base.FlipPage(pageIndex, forceRefresh); - + RefreshPageIndeButtonState(); } - public override PageInfo AddPageFirst(PageInfo pageInfo) + public override PageInfo AddPage(PageInfo pageInfo = null, bool isFirstOtherwiseLast = false) { if (pageInfo is not PageComponentInfo componentPageInfo) { - Debug.LogError($"页é�¢å®¹å™¨{Currentpage}ä¸�支æŒ�当å‰�管ç�†å™¨ï¼Œå…¶å¿…须由{nameof(FlipPageComponentManager)}.{nameof(PageComponentInfo)}继承/声å��,å�¦åˆ™æ— æ³•支æŒ�å�Žç»­åŠŸèƒ½", this); + Debug.LogError( + $"页é�¢å®¹å™¨{Currentpage}ä¸�支æŒ�当å‰�管ç�†å™¨ï¼Œå…¶å¿…须由{nameof(FlipPageComponentManager)}.{nameof(PageComponentInfo)}继承/声å��,å�¦åˆ™æ— æ³•支æŒ�å�Žç»­åŠŸèƒ½", + this); return null; } + // 页é�¢åŸºç¡€åˆ�始化 - var result = base.AddPageFirst(pageInfo); + var result = base.AddPage(pageInfo, isFirstOtherwiseLast); // 添加选择按钮 AddPageIndexButton(componentPageInfo); // 刷新选择按钮显示状æ€� @@ -288,30 +291,10 @@ namespace XericUI.FlipPage return result; } - public override PageInfo AddPageLast(PageInfo pageInfo) - { - if (pageInfo is not PageComponentInfo componentPageInfo) - { - Debug.LogError($"页é�¢å®¹å™¨{Currentpage}ä¸�支æŒ�当å‰�管ç�†å™¨ï¼Œå…¶å¿…须由{nameof(FlipPageComponentManager)}.{nameof(PageComponentInfo)}继承/声å��,å�¦åˆ™æ— æ³•支æŒ�å�Žç»­åŠŸèƒ½", this); - return null; - } - // 页é�¢åŸºç¡€åˆ�始化 - var result = base.AddPageLast(pageInfo); - // 添加选择按钮 - AddPageIndexButton(componentPageInfo); - // 刷新选择按钮显示状æ€� - RefreshPageIndeButtonState(); - // 刷新总页数 - RefreshLabelTextTotalPageCount(); - return result; - } - - - public override void RemovePage(int pageIndex) { base.RemovePage(pageIndex); - + pageButtonPool.DirectlyRelease(pageSelectButton[pageIndex].Target0.gameObject); pageSelectButton.RemoveAt(pageIndex); @@ -319,41 +302,45 @@ namespace XericUI.FlipPage RefreshLabelTextTotalPageCount(); } - public override void ClearPages() + public override void ClearPages(bool resetPool = true) { PageInfos .OfType() .Where(a => a.pageSelectableVessel.IsValidVessel()) .ForEachDo(a => pageButtonPool.DirectlyRelease(a.pageSelectableVessel!.Target0.gameObject)); pageSelectButton.Clear(); - base.ClearPages(); + base.ClearPages(resetPool); RefreshLabelTextTotalPageCount(); } /// - /// 在页é�¢ä¸Šæ·»åŠ æŒ‰é’® + /// 添加页é�¢å¯¹åº”的翻页按钮 /// /// protected virtual void AddPageIndexButton(PageComponentInfo pageInfo) { - var pageIndexSelectable = GetPageIndexButton(); - pageInfo.pageSelectableVessel = pageIndexSelectable; + // 检查页é�¢ä¸Šçš„æŒ‰é’®å¼•用 + ObjectVessel pageIndexSelectable = null; + if (pageInfo.pageSelectableVessel == null) + { + pageIndexSelectable = GetPageIndexButton(); + pageInfo.pageSelectableVessel = pageIndexSelectable; + } + else + pageIndexSelectable = pageInfo.pageSelectableVessel; + // 将按钮对象添加到列表中便于管ç�† pageSelectButton.Add(pageIndexSelectable); SwitchSelectableVesselType(pageIndexSelectable.Target0, - button => - { - button.onClick.AddListener(() => FlipPage(pageInfo.pageNumber)); - }, + button => { button.onClick.AddListener(() => FlipPage(pageInfo.pageNumber)); }, toggle => { toggle.isOn = pageInfo.pageNumber == currentPageIndex; toggle.group = ToggleGroup; toggle.onValueChanged.AddListener(b => { - if (b) - FlipPage(pageInfo.pageNumber); + if (b) FlipPage(pageInfo.pageNumber); }); }); RefreshPageSelectableVesselLabel(pageInfo); @@ -367,54 +354,54 @@ namespace XericUI.FlipPage var min = currentPageIndex - (int)(candidatesNumber / 2); min = Math.Max(min, 0); - min = pageSelectButton.Count - candidatesNumber > 0 - ? Math.Min(min, (int)(pageSelectButton.Count - candidatesNumber)) + min = pageSelectButton.Count - candidatesNumber > 0 + ? Math.Min(min, (int)(pageSelectButton.Count - candidatesNumber)) : 0; var max = min + (int)candidatesNumber; - + for (int i = 0; i < pageSelectButton.Count; i++) { pageSelectButton[i].Target0.transform.SetSiblingIndex(i); - + // 显示数é‡�控制 if (inMaximumCandidatesNumber) pageSelectButton[i].Target0.gameObject.SetActive(min <= i && i <= max); else pageSelectButton[i].Target0.gameObject.SetActive(min <= i && i < max); // 看ä¸�è§�的内容ä¸�刷新 - if (!pageSelectButton[i].Target0.gameObject.activeSelf) + if (!pageSelectButton[i].Target0.gameObject.activeSelf) continue; - + // 更新索引 pageSelectButton[i].Target1.text = MacroRegex.RegexReplace(pageIndexFormat, i + 1); - + // SwitchSelectableVesselType(pageSelectButton[i].Target0, // null, // toggle => // { // toggle.SetIsOnWithoutNotify(currentPageIndex == i); // }); - } + } } - + /// /// 更新总页数 /// private void RefreshLabelTextTotalPageCount() { if (labelTextTotalPageCount.IsValidVessel()) // 总页数更新 - labelTextTotalPageCount.Target.text = + labelTextTotalPageCount.Target.text = MacroRegex.RegexReplace(totalPageCountFormat, PageInfos.Count.ToString()); } - + /// /// 刷新翻页按钮索引为当å‰�页é�¢ç´¢å¼• /// public void RefreshPageSelectableVesselLabel(PageComponentInfo page, object customInput = null) { if (page.pageSelectableVessel.IsValidVessel()) - page.pageSelectableVessel!.Target1.text = - MacroRegex.RegexReplace(pageIndexFormat, customInput ?? page.pageNumber); + page.pageSelectableVessel!.Target1.text = + MacroRegex.RegexReplace(pageIndexFormat, customInput ?? page.pageNumber); } #endregion @@ -422,7 +409,7 @@ namespace XericUI.FlipPage #region 组件方法 /// - /// 获å�–页é�¢ç´¢å¼•按钮 + /// 获å�–页é�¢ç´¢å¼•按钮(获å�–这个按钮的池化对象,éš�å�Žåº”当将其绑定到页é�¢ä¸Š) /// /// protected virtual ObjectVessel GetPageIndexButton() @@ -433,40 +420,50 @@ namespace XericUI.FlipPage var vessel = new ObjectVessel(selectable, text); return vessel; } - - protected virtual void ListenPageSelectable(ObjectVessel selectableVessel, Action selectPageAction) + + /// + /// 注册一个委托到翻页按钮上。(事件会在调用容器清空å�Žè¢«è‡ªåŠ¨å›žæ”¶) + /// + /// + /// + protected virtual void ListenPageSelectable(ObjectVessel selectableVessel, + Action selectPageAction) { if (selectableVessel.Target0 is Button button) { - button.onClick.AddListener(() => - { - selectPageAction?.Invoke(currentPageIndex); - }); + button.onClick.AddListener(() => { selectPageAction?.Invoke(currentPageIndex); }); } } /// - /// 处ç�†å�¯é€‰å¯¹è±¡ç±»åž‹ï¼Œå¦‚æžœè¦�支æŒ�更多的类型优先改此方法,以便获得其他所有ä½�置的编译器æ��示 + /// 处ç�†å�¯é€‰å¯¹è±¡ç±»åž‹.(如果è¦�支æŒ�更多的类型,应优先改此方法,以便获得其他所有ä½�置的编译器æ��示) /// /// - /// - /// + /// 如果是按钮 + /// 如果是å�•选项 /// - protected static bool SwitchSelectableVesselType(Selectable selectable, Action public IEnumerable AllItemInfos => _pageInfos.SelectMany(page => page.itemInfos); - + /// /// Ò³ÃæÄ¬ÈÏ×î´óÏîÄ¿ÊýÁ¿ /// - protected int DefaultItemCountPerPage + protected int DefaultItemCountPerPage => defaultItemCountPerPage < 0 ? int.MaxValue : defaultItemCountPerPage; - + private List _backupItemInfos; public List BackItemInfos => _backupItemInfos; @@ -138,14 +136,27 @@ namespace XericUI.FlipPage /// ËùÓÐÒ³ÃæÊýÁ¿ /// public int TotalPageCount => PageInfos.Count(); - + +#if UNITY_EDITOR && ODIN_INSPECTOR + [LabelText("ËùÓÐÒ³Ãæ")] + [Obsolete("ÏÔʾµ÷ÊÔÁбí ÊôÐÔ½ö±à¼­Ê±ÓÐЧ£¬²»Òªµ÷ÓÃ")] + private List _pageInfoLists_ => _pageInfos.ToList(); +#endif + #endregion #region ÉúÃüÖÜÆÚ + protected override void Awake() + { + base.Awake(); + PageInfoPool = new ObjectPool(CreatPageInfo, GetPageInfo, ReleasePageInfo, DestroyPageInfo); + } + protected override void Start() { base.Start(); + FlipPage(currentPageIndex); } @@ -160,18 +171,20 @@ namespace XericUI.FlipPage #region ·­Ò³¹ÜÀí /// - /// µ±·¢Éú·­Ò³Ê±(Õâ»áÔÚÕû¸ö·­Ò³¶¯×÷Á÷³ÌµÄ×îºóÖ´ÐÐ) + /// µ±·¢Éú·­Ò³Ê±»Øµ÷ (Õâ»áÔÚÕû¸ö·­Ò³¶¯×÷Á÷³ÌµÄ×îºóÖ´ÐУ¬·­Ò³¹ý³ÌÖлص÷»áÔÚ´Ë֮ǰ²¥·Å) /// protected virtual void OnFlipPage() { - } - + /// - /// ͨ¹ýÖ¸ÁîÉ¸Ñ¡Ò³Ãæ + /// ͨ¹ýÖ¸Áî·­µ½Ò³Ãæ /// - /// - /// + /// + /// ÊÖ¶¯ÊäÈëÒ³ÊýʱִÐд˷½·¨¡£ + /// + /// Ò³Êý±àºÅ£¨»òÆäËûÃüÁµ«ÐèÒªÊÖ¶¯ÊµÏÖ´¦Àí£¬Ä¬ÈÏÖ»´¦ÀíÒ³Êý£© + /// Ç¿ÖÆË¢Ð£¨Ä¬ÈÏÇé¿öÏÂÈç¹ûµ±Ç°Ò³¾ÍÊÇÄ¿±êҳʱ²»»áÖ´ÐкóÐøµÄ·­Ò³¶¯×÷£© public virtual void FlipPage(string pageNumber, bool forceRefresh = false) { if (float.TryParse(pageNumber, out var index)) @@ -183,9 +196,14 @@ namespace XericUI.FlipPage /// /// ·­µ½Ö¸¶¨Ò³ /// - /// - /// ¿ìËÙ·­Ò³£¬ - /// + /// + /// ·­Ò³Ê±£¬µ±Ç°Ò³»á´¥·¢Ò»´Î OnPageInvisible£¬Ä¿±êÒ³»á´¥·¢Ò»´Î OnPageVisible£» + /// ·­µ½Ä¿±êÒ³Êý¹ý³ÌÖгýµ±Ç°Ò³ºÍÄ¿±êÒ³Ö®ÍâµÄËùÓÐÒ³Ãæ»á´¥·¢Ò»´ÎOnPageVisible£¬OnPageInvisibleµÄ¿ìËÙ·­Ò³£» + /// ÔÚÖØÐ´Ïà¹ØÊ¼þʱ£¬ÀûÓÿìËÙ·­Ò³×´Ì¬¿ÉÒÔÌø¹ý¶¯»­¼ÓÔØ£¬½öÖ´ÐÐÏà¹ØµÄ´¥·¢Æ÷¡£ + /// Èç¹ûѹ¸ù²»Ï£Íûµ÷ÓÃÆÚ¼äËùÓÐÒ³ÃæµÄ·­Ò³ä¯ÀÀʼþ£¬¿ÉÒÔÖ´ÐÐ JumpPage¡£ + /// + /// Ä¿±êÒ³Êý + /// Ç¿ÖÆË¢Ð£¨Ä¬ÈÏÇé¿öÏÂÈç¹ûµ±Ç°Ò³¾ÍÊÇÄ¿±êҳʱ²»»áÖ´ÐкóÐøµÄ·­Ò³¶¯×÷£© public virtual void FlipPage(int pageIndex, bool forceRefresh = false) { // ¼ì²é·­Ò³Ë÷ÒýÓÐЧ @@ -200,33 +218,33 @@ namespace XericUI.FlipPage // ·­Ò³¼ÆËã var pageIndexOffset = pageIndex - currentPageIndex; var lastPageIndex = currentPageIndex; - // Èç¹û½Úµã²»´æÔÚ£¬Í¨¹ýË÷ÒýѰÕÒ + var quickPage = false; // ¿ìËÙä¯ÀÀÒ³ + bool visitOffsetDirIsNext; + // Èç¹û½Úµã²»´æÔÚ£¬Í¨¹ýË÷ÒýÖ±½ÓÃüÖÐ if (CurrentPageNode == null) + { CurrentPageNode = _pageInfos.GetOrderNode().LandedIndex(currentPageIndex); - // Èç¹ûË÷ÒýÆ«ÒÆ£¬Öð¸öÒÆ¶¯ - else if (pageIndexOffset > 0) - { - // ÏȹرÕÒ³ÃæÔªËØ - CurrentPageNode.Value.CallChildItemInvisible(); - for (var i = 0; i < pageIndexOffset; i++) - { - var next = CurrentPageNode!.Next; - SwitchPage(next, _pageInfos.Last, i + 1 < pageIndexOffset); - } + if (CurrentPageNode == null) + Debug.LogError($"Ë÷Òý{currentPageIndex}ϵĽڵ㲻´æÔÚ, Çë¼ì²éºóÔÙÊÔ", this); + else + Currentpage.OnPageVisible(false); } - else if (pageIndexOffset < 0) + // Èç¹ûË÷ÒýÆ«ÒÆ£¬Öð¸öÒÆ¶¯ + else if (pageIndexOffset != 0) { + // ÅжϷ½Ïò + visitOffsetDirIsNext = pageIndexOffset > 0; + pageIndexOffset = Mathf.Abs(pageIndexOffset); // ÏȹرÕÒ³ÃæÔªËØ CurrentPageNode.Value.CallChildItemInvisible(); - for (var i = 0; i > pageIndexOffset; i--) - { - var previa = CurrentPageNode!.Previous; - SwitchPage(previa, _pageInfos.First, i - 1 > pageIndexOffset); - } + for (var i = 1; i < pageIndexOffset; i++) + SwitchPage(false); + SwitchPage(true); } // ûÓз­¶¯ÓÐЧҳ£¬Ö±½ÓÍ˳ö else return; + // ¿ÉÄÜʱµ±Ç°²»´æÔÚÈκÎÒ³Ãæ if (CurrentPageNode == null) return; @@ -234,26 +252,43 @@ namespace XericUI.FlipPage CurrentPageNode.Value.CallChildItemVisible(); currentPageIndex = pageIndex; OnFlipPage(); - - // ·­Ò³ - void SwitchPage(LinkedListNode newPageNode, LinkedListNode defualtPageNode, bool quickPage) - { - if (newPageNode != null) - { - Currentpage.OnPageInvisible(quickPage); - CurrentPageNode = newPageNode; - Currentpage.OnPageVisible(quickPage); - } + return; - if (canPassIndexBoundary) - { - Currentpage.OnPageInvisible(quickPage); - CurrentPageNode = defualtPageNode; - Currentpage.OnPageVisible(quickPage); - } + void SwitchPage(bool isEndPage) + { + Currentpage.OnPageInvisible(quickPage); + quickPage = !isEndPage; + CurrentPageNode = visitOffsetDirIsNext ? CurrentPageNode.Next : CurrentPageNode.Previous; + if (CurrentPageNode == null && canPassIndexBoundary) + CurrentPageNode = visitOffsetDirIsNext ? _pageInfos.First : _pageInfos.Last; + Currentpage.OnPageVisible(quickPage); } } + /// + /// ¾¶Ö±Ìø×ªµ½Ò³ (skip quick Page) + /// + /// + /// Ïà±È FlipPage ·½·¨£¬JumpPage»áÖ±½Ó¿Õ½µµ½Ò³£¬²»»áµ÷ÓÃÆÚ¼äÆäËûÒ³µÄä¯ÀÀʼþ¡£ + /// + public virtual void JumpPage(int pageIndex, bool forceRefresh = false) + { + // ×ÓÏîÒþ²Ø + CurrentPageNode?.Value.CallChildItemInvisible(); + + // ¼ÆËãË÷Òý¶ÔÓ¦µÄÒ³Ãæ + var page = _pageInfos.First; + while (pageIndex-- > 0 && page.Next != null) + page = page.Next; + // Ö»Ö´ÐзǿìËÙä¯ÀÀµÄ»Øµ÷ + Currentpage?.OnPageInvisible(false); + CurrentPageNode = page; + Currentpage?.OnPageVisible(false); + currentPageIndex = pageIndex; + // ×ÓÏîÏÔʾ + CurrentPageNode?.Value.CallChildItemVisible(); + } + /// /// ·­µ½¿ªÍ· /// @@ -290,24 +325,34 @@ namespace XericUI.FlipPage public void FlipPageToEnd() => FlipPage(_pageInfos.Count - 1); - - + /// /// Ìí¼ÓÒ³ÃæÔÚ¿ªÍ· /// - public virtual PageInfo AddPageFirst(PageInfo pageInfo) + /// + /// ×¢ÒâÍ³Ò»Ò³ÃæÀàÐÍ£¬Èç¹ûûÓÐÖ¸¶¨×Ô¶¨ÒåµÄÒ³Ãæ£¬ÄÇô + /// + public virtual PageInfo AddPage(PageInfo pageInfo = null, bool isFirstOtherwiseLast = false) { if (pageInfo == null) + pageInfo = PageInfoPool.Get(); + else + GetPageInfo(pageInfo); + + if (isFirstOtherwiseLast) { - Debug.LogError($"²»ÄÜÌí¼ÓÒ»¸ö¿ÕµÄÒ³ÃæÄÚÈݵ½¹ÜÀíÆ÷ÖУ¡", this); - return null; + // Ìí¼ÓÒ³Ãæ(Ò³ÃæÏ±êĬÈÏ0) + _pageInfos.AddFirst(pageInfo); + // ¸üкóÃæÒ³ÃæµÄË÷Òý + RefreshAllPageNumber(); + } + else + { + // Ìí¼ÓÒ³ÃæÏ±ê + pageInfo.pageNumber = _pageInfos.Count; + // Ìí¼ÓÒ³Ãæ + _pageInfos.AddLast(pageInfo); } - // Ìí¼ÓÒ³ÃæÏ±ê - pageInfo.pageNumber = 0; - // Ìí¼ÓÒ³Ãæ - _pageInfos.AddFirst(pageInfo); - // ¸üкóÃæÒ³ÃæµÄË÷Òý - RefreshAllPageNumber(); // Ö´ÐÐÒ³ÃæÉúÃüÖÜÆÚ pageInfo.OnPageCreated(this); // Ë¢ÐÂÒ³Ãæ @@ -315,49 +360,20 @@ namespace XericUI.FlipPage return pageInfo; } - /// - /// Ìí¼ÓÒ³ÃæÔÚ½áβ - /// - public virtual PageInfo AddPageLast(PageInfo pageInfo) - { - if (pageInfo == null) - { - Debug.LogError($"²»ÄÜÌí¼ÓÒ»¸ö¿ÕµÄÒ³ÃæÄÚÈݵ½¹ÜÀíÆ÷ÖУ¡", this); - return null; - } - // Ìí¼ÓÒ³ÃæÏ±ê - pageInfo.pageNumber = _pageInfos.Count; - // Ìí¼ÓÒ³Ãæ - _pageInfos.AddLast(pageInfo); - // Ö´ÐÐÒ³ÃæÉúÃüÖÜÆÚ - pageInfo.OnPageCreated(this); - // Ë¢ÐÂÒ³Ãæ - FlipPage(currentPageIndex, true); - return pageInfo; - } - /// /// °´¶ÔÏóÒýÓÃɾ³ýÒ³Ãæ /// /// public virtual void RemovePage(PageInfo pageInfo) { - // Èç¹ûÒÆ³ýµÄÊǵ±Ç°Ò³Ã棬ִÐйرղÙ×÷ - if (CurrentPageNode.Value == pageInfo) - { - pageInfo.OnPageInvisible(true); - CurrentPageNode = null; - } - // Ö´ÐÐÒ³ÃæÉúÃüÖÜÆÚ - pageInfo.OnPageDestroy(this); - // Ò³ÃæË÷ÒýÒÆ³ý - _pageInfos.Remove(pageInfo); + // ÊÍ·ÅÒ³Ãæ + PageInfoPool.Release(pageInfo); // Ë¢ÐÂÒ³Ãæ FlipPage(currentPageIndex, true); var index = PageInfos.IndexOf(a => a == pageInfo); RemovePage(index); } - + /// /// ÒÆ³ýÒ³Ãæ£¨Ò³ÃæÉϵÄÊý¾ÝÄÚÈÝÒ²»áÒ»Í¬ÒÆ³ý£© /// @@ -368,26 +384,20 @@ namespace XericUI.FlipPage Debug.LogError($"²»ÄÜÒÆ³ý²»ÔÚ·¶Î§ÄÚµÄË÷Òý{pageIndex}£¡", this); return; } + // »ñÈ¡Ò³Ãæ½Úµã var page = _pageInfos.GetOrderNode().LandedIndex(pageIndex); // ¸üкóÃæÒ³ÃæµÄË÷Òý var tempPage = page; - var tempPageNumber = page.Value.pageNumber; + var tempPageNumber = page.Value.pageNumber; while (tempPage.Next != null) { tempPage = tempPage.Next; tempPage.Value.pageNumber = tempPageNumber++; } - // Èç¹ûÒÆ³ýµÄÊǵ±Ç°Ò³Ã棬ִÐйرղÙ×÷ - if (CurrentPageNode == page) - { - page.Value.OnPageInvisible(true); - CurrentPageNode = null; - } - // Ö´ÐÐÒ³ÃæÉúÃüÖÜÆÚ - page.Value.OnPageDestroy(this); - // Ò³ÃæË÷ÒýÒÆ³ý - _pageInfos.Remove(page); + + // ÊÍ·ÅÒ³Ãæ + PageInfoPool.Release(page.Value); // Ë¢ÐÂÒ³Ãæ FlipPage(currentPageIndex, true); } @@ -402,7 +412,7 @@ namespace XericUI.FlipPage RemovePage(pageIndex); RestoreItemsToPages(); } - + /// /// »ñÈ¡Ë÷ÒýϵÄÒ³Ãæ /// @@ -412,7 +422,7 @@ namespace XericUI.FlipPage public T IndexOfPageInfo(int pageIndex) where T : PageInfo => IndexOfPageInfo(pageIndex) as T; - + /// /// »ñÈ¡Ë÷ÒýϵÄÒ³Ãæ /// @@ -421,20 +431,75 @@ namespace XericUI.FlipPage /// public PageInfo IndexOfPageInfo(int pageIndex) => _pageInfos.LandedIndex(pageIndex); - + /// /// Çå³ýËùÓÐÒ³Ãæ (ËùÓÐÒ³ÃæÊý¾ÝÒ²»áÒ»Í¬ÒÆ³ý) /// + /// Í¬Ê±ÖØÖÃÒ³Ãæ³Ø + /// + /// Ò³ÃæµÄÒýÓûá´Ó¹ÜÀíÆ÷ÖÐÊÍ·Å£¬Í¬Ê±ÐèÒª×ÔÐÐÖØÐ´Ò³Ãæ OnPageDestroy È·±£Ò³Ãæ×¼È·ÊÍ·ÅÁ˸÷ÖÖ¶«Î÷¡£ + /// ³ý·ÇÄãÈ·ÈÏÄãµÄÒ³ÃæÊý¾Ý¶ÔÏóÀàÐÍÊÇÒ»Öµģ¬·ñÔòÎÞÂÛÈçºÎ¶¼½¨ÒéÇå¿ÕÒ³ÃæÊ±Ò²Çå¿Õ¶ÔÏ󳨣¬²»È»»á´øÀ´ÑÏÖØµÄÀàÐÍÎÛȾ¡£ + /// #if ODIN_INSPECTOR [HorizontalGroup("Êý¾Ý"), Button("Çå³ýËùÓÐÒ³Ãæ")] #endif - public virtual void ClearPages() + public virtual void ClearPages(bool resetPool = true) { - _pageInfos.Clear(); + if (CurrentPageNode != null) + Currentpage.OnPageInvisible(true); + foreach (var pageInfo in _pageInfos) + { + pageInfo.itemInfos.Clear(); + if (resetPool) + PageInfoPool.Release(pageInfo); + else + ReleasePageInfo(pageInfo); // Ö±½Óµ÷ÓÃÊÍ·Åʼþ£¬²»×ß¶ÔÏ󳨣¬²»ÖªµÀÕâÑùÄܲ»ÄܼõÉÙÖØ¸´µÄÈëÕ»¿ªÏú£¿»¹ÊÇ»áÈÃgc±äµÃË鯬»¯£¿ + } + // Çå¿Õ³Ø + if (resetPool) + PageInfoPool.Clear(); + // ÖØÖõ±Ç°Ò³Ãæ CurrentPageNode = null; currentPageIndex = 0; + // Çå¿Õ»º´æ + _pageInfos.Clear(); + _itemInfos.Clear(); } - + + /// + /// ¹Ø±ÕËùÓÐÒ³Ãæ + /// + public void InactivePages() => SetPagesActive(false); + + /// + /// ÖØÐ¼¤»îËùÓÐÒ³Ãæ + /// + public void ReactivePages() => SetPagesActive(true); + + /// + /// ÉèÖÃËùÓÐÒ³ÃæµÄ¼¤»î״̬ + /// + /// + public void SetPagesActive(bool active) + { + foreach (var pageInfo in _pageInfos) + pageInfo.pageActive = active; + FlipPage(0, true); + } + + /// + /// ʹÓÃ×Ô¶¨ÒåµÄ·½·¨ÉèÖü¤»î״̬ + /// + /// + /// + public void SetPagesActive(Func isActive) + where T : PageInfo + { + foreach (var pageInfo in _pageInfos) + pageInfo.pageActive = isActive((T)pageInfo); + FlipPage(0, true); + } + /// /// ½»»»ABÒ³Ãæ /// @@ -461,44 +526,96 @@ namespace XericUI.FlipPage page.pageNumber = index++; } } - + + #endregion + + #region Êý¾ÝÏîÄ¿³Ø + + /// + /// ¶¨Òå¶ÔÏó³ØÈçºÎ´´½¨Ò³Ã棨½¨ÒéÖ±½Ó¸²¸ÇίÍУ© + /// + /// + protected virtual PageInfo CreatPageInfo() => HowToCreatPageInfo(); + + /// + /// ¶¨Òå¶ÔÏó³ØÈçºÎÖ´ÐлñÈ¡Ò³ÃæºóµÄʼþ + /// + /// + protected virtual void GetPageInfo(PageInfo info) + { + info.pageNumber = 0; + _pageInfos.AddLast(info); + } + + /// + /// ¶¨Òå¶ÔÏó³ØÈçºÎÖ´ÐÐÊÍ·ÅÒ³ÃæºóµÄʼþ + /// + /// + protected virtual void ReleasePageInfo(PageInfo info) + { + if (CurrentPageNode != null && Currentpage == info) + { + info.OnPageInvisible(true); + CurrentPageNode = null; + } + + info.OnPageDestroy(this); + _pageInfos.Remove(info); + } + + /// + /// ¶¨Òå¶ÔÏó³ØÈçºÎÖ´ÐÐÏú»ÙÒ³ÃæºóµÄʼþ + /// + /// + protected virtual void DestroyPageInfo(PageInfo info) + { + } + #endregion #region Êý¾ÝÏîÄ¿ /// - /// Ìí¼ÓÊý¾ÝÏîÄ¿ + /// Ìí¼ÓÒ»×éÊý¾ÝÏîÄ¿(·½·¨´ýÓÅ»¯) /// - /// - /// - public virtual void AddItem(ItemInfo item) + /// + /// + public virtual void AddItems(IEnumerable items, Func customGetPage = null) { - AddItem(item, () => throw new Exception("ÐèÒª·­Ò³¹ÜÀíÆ÷ʵÏÖÏàÓ¦µÄÒ³Ãæ´´½¨Âß¼­£¬²¢ÖØÐ´Ìí¼ÓĬÈÏÊý¾Ý·½·¨ºó²Å¿ÉÒÔʹÓá£")); + foreach (var item in items) + AddItem(item, customGetPage); } - + /// /// Ìí¼ÓÊý¾ÝÏîÄ¿ /// - public virtual void AddItem(ItemInfo item, Func addPage) + /// + /// Ìṩһ¸öÖ¸¶¨µÄÊý¾ÝÀàÐÍ£¬Ä¬ÈÏÌí¼ÓÕâ¸öÀàÐ͵ÄÒ³Ãæ + public virtual void AddItem(ItemInfo item) + where T : PageInfo, new() + => AddItem(item, () => new T()); + + /// + /// Ìí¼ÓÊý¾ÝÏîÄ¿ + /// + /// + /// Ìí¼ÓÏîÄ¿µ½Ò³ÃæÖУ¬ + /// + public virtual void AddItem(ItemInfo item, Func customGetPage = null) { - // ÏòǰѰÕÒ¿Õȱ£¨ÕâÔÚÒ³Ãæ¶¼±»×¼È·Ìî³äµÄÇé¿öÏÂ×îÓÇ£© - var firstVacancy = _pageInfos - .GetReversedOrderNode() - .LastOrDefault(a - => a.Value.itemInfos.Count < DefaultItemCountPerPage); - if (firstVacancy != null) + var page = _pageInfos.Count <= 0 ? null : _pageInfos.Last.Value; + if (page != null && + page.CheckPageAnyLack(item) && + page.itemInfos.Count < DefaultItemCountPerPage) { - firstVacancy.Value.itemInfos.Add(item); + page.itemInfos.Add(item); _itemInfos.Add(item); return; } - if (addPage == null) - { - Debug.LogError("µ±Ç°Ò³ÃæÒÑÂú£¬Êý¾ÝÏîÄ¿ÆÚÍû˳λÌí¼Óµ½ÐÂÒ³ÃæÖУ¬µ«Î´Ö¸¶¨Ò³Ãæ´´½¨º¯Êý£¬Ìí¼Ó¹ý³ÌÒÑÍ˳ö", this); - return; - } + // н¨Ò»¸öÒ³Ãæ´æ·ÅÊý¾Ý - addPage.Invoke().itemInfos.Add(item); + page = customGetPage == null ? PageInfoPool.Get() : customGetPage(); + page.itemInfos.Add(item); _itemInfos.Add(item); } @@ -508,35 +625,16 @@ namespace XericUI.FlipPage /// public virtual void RemoveItem(ItemInfo item) { + _itemInfos.Remove(item); foreach (var a in AllItemInfos .Adjoint() .Where(a => a.obj == item) .Reverse()) { ItemIndex2PageIndex(a.index); - } } - public virtual void RemoveItem(int indexItem) - { - - } - - /// - /// ±£ÁôÒ³ÃæµÄ״̬ÏÂÇå¿ÕËùÓÐÊý¾Ý - /// -#if ODIN_INSPECTOR - [HorizontalGroup("Êý¾Ý"), Button("Çå³ýËùÓÐÊý¾Ý")] -#endif - public void ClearItemsWithoutPages() - { - foreach (var page in _pageInfos) - { - page.itemInfos.Clear(); - } - } - /// /// ʹÓÃË÷Òý¶¨Î»µ½Êý¾Ý /// @@ -553,9 +651,7 @@ namespace XericUI.FlipPage /// /// public virtual int ItemIndex2PageIndex(int itemIndex) - { - return itemIndex / DefaultItemCountPerPage; - } + => itemIndex / DefaultItemCountPerPage; /// /// µ±Ç°·­Ò³¹ÜÀíÆ÷Öаüº¬¸ø¶¨Êý¾ÝÏîÄ¿ @@ -564,8 +660,8 @@ namespace XericUI.FlipPage /// public bool Contains(ItemInfo item) => _itemInfos.Contains(item); - - + + /// /// »ñÈ¡±¸·ÝËùÓÐÊý¾ÝÏîÄ¿ /// @@ -580,9 +676,10 @@ namespace XericUI.FlipPage BackupItemsFormPages(); return _backupItemInfos.OfType(); } + return AllItemInfos.OfType(); } - + /// /// ±¸·ÝËùÓÐÊý¾ÝÏîÄ¿ /// @@ -593,60 +690,45 @@ namespace XericUI.FlipPage } /// - /// Ç¿ÖÆÖØÅÅËùÓÐÊý¾ÝÏîÄ¿£¨´Ó±¸·ÝÖлָ´Êý¾Ý£© + /// ÖØÅÅËùÓÐÊý¾ÝÏîÄ¿£¨´Ó±¸·ÝÖлָ´Êý¾Ý£© /// public void RestoreItemsToPages() - { - RestoreItemsToPages(_backupItemInfos); - } + => RestoreItemsToPages(_backupItemInfos); + /// - /// Ç¿ÖÆÖØÅÅËùÓÐÊý¾ÝÏîÄ¿£¨´Ó±¸·ÝÖÐͨ¹ý¹ýÂËÆ÷»Ö¸´Êý¾Ý£© + /// ÖØÅÅËùÓÐÊý¾ÝÏîÄ¿£¨»ùÓÚ±¸·ÝÊý¾ÝÓ¦ÓùýÂËÆ÷µÄÊý¾Ý£© /// public void RestoreItemsByFilterToPages() - { - RestoreItemsToPages(_backupItemInfos.Where(a => a.PassFilter(this)).ToList()); - } - + => RestoreItemsToPages(_backupItemInfos.Where(a => a.PassFilter(this)).ToList()); + /// - /// Ç¿ÖÆÖØÅÅËùÓÐÊý¾ÝÏîÄ¿£¨´Ó¸ø¶¨±¸·ÝÖлָ´Êý¾Ý£© + /// ÖØÅÅËùÓÐÊý¾ÝÏîÄ¿£¨´Ó¸ø¶¨±¸·ÝÖлָ´Êý¾Ý£© /// - public void RestoreItemsToPages(List overrideDatas) - where T : ItemInfo + /// + /// ÖØÐÂÅÅÁÐÉæ¼°Ò³Ãæ²¼¾ÖÕûÀí + /// + /// + public void RestoreItemsToPages(List overrideDatas, Func customGetPage = null, + bool allowClear = true) + where TItemInfo : ItemInfo { - if (overrideDatas == null || overrideDatas.Count <= 0) + var collectionInvalid = overrideDatas is not { Count: > 0 }; + if (collectionInvalid && !allowClear) { - Debug.LogError($"ÖØÅÅÊý¾ÝÐèÒªÒ»¸öÓÐЧµÄÊý¾Ý¶ÔÏóÁÐ±í£¬Èç¹ûÏ£Íû½«Êý¾ÝÖØÖÃΪ¿Õ£¬¿ÉÒÔʹÓÃClear·½·¨£¬¶ø²»ÊÇÖØÅŲÙ×÷¡£", this); + Debug.LogError($"µ±Ç°ÖØÅÅÊý¾ÝÆÚÍûʹÓÃÒ»¸öÓÐЧµÄÊý¾Ý¶ÔÏóÁÐ±í£¬ÈçÏ£Íû½«Êý¾ÝÖØÖÃΪ¿Õ£¬¿ÉÒÔʹÓÃClear·½·¨£¬»òÖØÐÂÔÊÐíÖØÅŲÙ×÷Çå¿ÕÁÐ±í¡£", this); return; } - if (ItemIndex2PageIndex(overrideDatas.Count - 1) > _pageInfos.Count) - { - Debug.LogError($"ÖØÅÅÊý¾Ýʱ£¬Ô­ÓÐÊý¾ÝÊýÁ¿({overrideDatas.Count})³¬³öÏÖÓÐÃæ°åÊýÁ¿({_pageInfos.Count})£¬ÒѾܾøÖØÅÅ", this); - return; - } - // Ö´ÐÐÖØÅÅ - var page = _pageInfos.First; - page.Value.itemInfos.Clear(); - var pageIndex = 0; - for (int i = 0; i < overrideDatas.Count; i++) - { - var newPageIndex = ItemIndex2PageIndex(i); - if (pageIndex != newPageIndex) - { - pageIndex = newPageIndex; - page = page.Next; - if (page == null) - { - Debug.LogError($"ÖØÅÅÊý¾Ýʱ£¬Ò³ÃæÁ´½Ó´íÎó£¬ÖØÅű»ÆÈÖжÏ", this); - return; - } - page.Value.itemInfos.Clear(); - } - page.Value.itemInfos.Add(overrideDatas[i]); - } + + // Çå¿ÕÒ³Ãæ + ClearPages(); + if (collectionInvalid) return; + AddItems(overrideDatas, customGetPage); + FlipPage(0); + return; } #endregion - + #region ÀàÄÚÀàÐÍ /// @@ -681,6 +763,8 @@ namespace XericUI.FlipPage #endif public int pageNumber { get; internal set; } + public bool pageActive; + #endregion #region ÉúÃüÖÜÆÚ @@ -705,49 +789,65 @@ namespace XericUI.FlipPage // ÊÍ·ÅÁбí if (itemInfos != null) ListPool.Release(itemInfos); - } /// - /// Ò³ÃæÏÔʾʱ + /// Ò³ÃæÏÔʾʱ»Øµ÷ /// /// ¿ìËÙä¯ÀÀ(ÓÃÓÚÇø·Ö¶¯»­ºÍÂß¼­£¬ÎªÕæÊ±£¬²»Ó¦µ±ÔÚ¶¯»­Ê¼þºó¼ÌÐø¼ÓÔØÊý¾Ý) - /// - /// Ò³ÃæÖеijÉÔ±»á×Ô¶¯ÔÚ·Ç¿ìËÙä¯ÀÀģʽÏÂ×Ô¶¯Ö´ÐÐÏàÓ¦µÄ¼¤»îº¯Êý - /// + /// + /// Ò³ÃæÖеijÉÔ±»á×Ô¶¯Ö´ÐÐÆäÏàÓ¦µÄ¼¤»îº¯Êý£¬²»ÐèÒªÔÚÕâÀïÊÖ¶¯µ÷Óᣠ+ /// ¿ìËÙä¯ÀÀÖ÷ҪΪÁËÇø·Öµ±Ç°Ö´ÐеÄÊǶ¯»­Ê¼þ»¹ÊÇ´¿Âß¼­¡£ + /// protected internal abstract void OnPageVisible(bool quickVisit); - + /// - /// Ò³ÃæÒþ²ØÊ± + /// Ò³ÃæÒþ²ØÊ±»Øµ÷ /// /// ¿ìËÙä¯ÀÀ(ÓÃÓÚÇø·Ö¶¯»­ºÍÂß¼­£¬ÎªÕæÊ±£¬²»Ó¦µ±ÔÚ¶¯»­Ê¼þºó¼ÌÐø¼ÓÔØÊý¾Ý) - /// - /// Ò³ÃæÖеijÉÔ±»á×Ô¶¯ÔÚ·Ç¿ìËÙä¯ÀÀģʽÏÂ×Ô¶¯Ö´ÐÐÏàÓ¦µÄ¼¤»îº¯Êý - /// + /// + /// Ò³ÃæÖеijÉÔ±»á×Ô¶¯Ö´ÐÐÆäÏàÓ¦µÄ¼¤»îº¯Êý£¬²»ÐèÒªÔÚÕâÀïÊÖ¶¯µ÷Óᣠ+ /// ¿ìËÙä¯ÀÀÖ÷ҪΪÁËÇø·Öµ±Ç°Ö´ÐеÄÊǶ¯»­Ê¼þ»¹ÊÇ´¿Âß¼­¡£ + /// protected internal abstract void OnPageInvisible(bool quickVisit); #endregion /// - /// ´«µÝ×ÓÏ»î»Øµ÷ʼþ + /// ×ÓÏ»î»Øµ÷£¨Ó¦ºô½Ð×ÓÏ»î£© /// + /// + /// ½öÒ³Ãæ´¥·¢¿ìËÙä¯ÀÀ£¬×ÓÏîûÓÐÕâ¸ö¹¦ÄÜ + /// protected internal virtual void CallChildItemVisible() { itemInfos .Where(a => a != null) .ForEachDo(itemInfo => itemInfo.OnItemVisible()); } - + /// - /// ´«µÝ×ÓÏî·Ç¼¤»î»Øµ÷ʼþ + /// ×ÓÏî·Ç¼¤»î»Øµ÷£¨Ó¦ºô½Ð×ÓÏîÒþ²Ø£© /// + /// + /// ½öÒ³Ãæ´¥·¢¿ìËÙä¯ÀÀ£¬×ÓÏîûÓÐÕâ¸ö¹¦ÄÜ + /// protected internal virtual void CallChildItemInvisible() { itemInfos .Where(a => a != null) .ForEachDo(itemInfo => itemInfo.OnItemInvisible()); } - + + /// + /// ¼ì²éÒ³ÃæÊÇ·ñ´æÔÚ¿ÉÒÔ·Å϶ÔÏóµÄ¿Õȱ + /// + /// + protected internal virtual bool CheckPageAnyLack(ItemInfo item = null) + { + return true; + } + public override string ToString() { return $"[{nameof(PageInfo)}] ({name})"; @@ -780,7 +880,7 @@ namespace XericUI.FlipPage #region ÉúÃüÖÜÆÚ /// - /// µ±ÏîÄ¿ÏÔʾʱ + /// µ±ÏîÄ¿ÏÔʾʱ»Øµ÷ /// /// /// Õâ»áÔÚÒ³ÃæÏÔʾ֮ºóÖ´ÐÐ @@ -788,7 +888,7 @@ namespace XericUI.FlipPage protected internal abstract void OnItemVisible(); /// - /// µ±ÏîÄ¿Òþ²ØÊ± + /// µ±ÏîÄ¿Òþ²ØÊ±»Øµ÷ /// /// /// Õâ»áÔÚÒ³Ãæ¹Ø±Õ֮ǰִÐÐ @@ -797,7 +897,7 @@ namespace XericUI.FlipPage #endregion - + /// /// ÊÇ·ñͨ¹ý¹ýÂËÆ÷ /// @@ -807,7 +907,7 @@ namespace XericUI.FlipPage { return true; } - + public override string ToString() { return $"[{nameof(ItemInfo)}] ({name})"; @@ -815,6 +915,5 @@ namespace XericUI.FlipPage } #endregion - } } \ No newline at end of file