using System; using System.Collections.Generic; using System.IO; using System.Linq; using FairyGUI; using FGUI.LG_secretAlbums; using FGUI.ZM_Common_01; using SGModule.Common.Helper; using SGModule.NetKit; using UnityEngine; namespace BallKingdomCrush { public class SecretAlbumsUI : BaseUI { private const int MaxVisibleCount = 6; // 一屏显示6个 private const int PreloadCount = 2; // 上下各预加载一屏 private readonly Dictionary _fileIsExist = new(); private readonly Dictionary activeLoaders = new(); private SecretAlbumsUICtrl ctrl; private SecretAlbumsModel model; private com_scAlbums ui; public SecretAlbumsUI(SecretAlbumsUICtrl ctrl) : base(ctrl) { uiName = UIConst.SecretAlbumsUI; this.ctrl = ctrl; } protected override void SetUIInfo(UIInfo uiInfo) { uiInfo.packageName = "LG_secretAlbums"; uiInfo.assetName = "com_scAlbums"; uiInfo.layerType = UILayerType.Popup; uiInfo.isNeedOpenAnim = false; uiInfo.isNeedCloseAnim = false; uiInfo.isNeedUIMask = true; } #region 生命周期 protected override void OnInit() { //model = ModuleManager.Instance.GetModel(ModelConst.SecretAlbumsModel) as SecretAlbumsModel; // 初始化GLoader池,设置最大缓存数 GLoaderPool.Instance.Init(null, 10, 464, 642); } protected override void OnClose() { // 1. 解除 UI 对 Loader 的引用 for (var i = 0; i < ui.sc_list.numChildren; i++) { var item = ui.sc_list.GetChildAt(i) as item_scalnums; if (item != null && item.com_pic.picture != null) item.com_pic.picture = null; // 清掉 GLoader 引用 } activeLoaders.Clear(); _fileIsExist.Clear(); GLoaderPool.Instance.DisposeAll(); TextureHelper.ClearMaterialPool(); // 强制卸载未使用的资源 // Resources.UnloadUnusedAssets(); // MemoryManager.CleanMemoryMonitor(); } protected override void OnBind() { ui = baseUI as FGUI.LG_secretAlbums.com_scAlbums; } private List _secretData = new List(); private List _secretData1 = new List(); protected override void OnOpenBefore(object args) { if (Screen.safeArea.y != 0) { ui.btn_gold.y += 68; ui.btn_close.y += 68; ui.sc_list.y += 68; } var eventName = GameHelper.IsAdModelOfPay() ? ADEventTrack.AD_Event : ADEventTrack.MaxPayEvent; TrackKit.SendEvent(eventName, ADEventTrack.Property.secret_albums_show); _secretData = ConfigSystem.GetSecretAlbumsConfig(); InitView(); } protected override void OnOpen(object args) { } protected override void OnHide() { } protected override void OnDisplay(object args) { } #endregion #region 消息 protected override void AddListener() { GameDispatcher.Instance.AddListener(GameMsg.UnlockSecretSuccess, UnlockSuccess); GameDispatcher.Instance.AddListener(GameMsg.Gold_refresh, set101); } protected override void RemoveListener() { GameDispatcher.Instance.RemoveListener(GameMsg.UnlockSecretSuccess, UnlockSuccess); GameDispatcher.Instance.RemoveListener(GameMsg.Gold_refresh, set101); } #endregion void UnlockSuccess(object str = null) { ui.btn_gold.GetChild("text_gold").text = GameHelper.Get101Str(); ui.sc_list.itemRenderer = ItemRender; ui.sc_list.numItems = _secretData.Count; } private void set101(object obj) { ui.btn_gold.GetChild("text_gold").text = GameHelper.Get101Str(); } //初始化页面逻辑 private void InitView() { ui.btn_gold.GetChild("text_gold").text = GameHelper.Get101Str(); ui.btn_close.SetClick(CtrlCloseUI); UnlockSuccess(); InitScroll(); } private void InitScroll() { ui.sc_list.scrollPane.onScroll.Add(OnScrollUpdate); ui.sc_list.scrollPane.onScrollEnd.Add(OnScrollEnd); // 保留结束时的整理 OnScrollEnd(); } // 滑动过程中实时更新 private void OnScrollUpdate() { UpdateVisibleAndPreload(); } // 核心刷新逻辑 private void UpdateVisibleAndPreload() { if (_secretData == null || _secretData.Count == 0) return; var firstVisibleIndex = ui.sc_list.GetFirstChildInView(); var lastVisibleIndex = Mathf.Min(firstVisibleIndex + MaxVisibleCount - 1, ui.sc_list.numItems - 1); var startIndex = Mathf.Max(0, firstVisibleIndex - PreloadCount); var endIndex = Mathf.Min(ui.sc_list.numItems - 1, lastVisibleIndex + PreloadCount); // 回收超出范围 loader var keysToRemove = new List(); foreach (var kv in activeLoaders) { var idx = kv.Key; if (idx < startIndex || idx > endIndex) { GLoaderPool.Instance.ReturnLoader(kv.Value); var oldItem = ui.sc_list.GetChildAt(idx) as item_scalnums; if (oldItem != null) oldItem.com_pic.picture = null; keysToRemove.Add(idx); } } foreach (var k in keysToRemove) activeLoaders.Remove(k); // 分配 loader 并加载图片 for (var i = startIndex; i <= endIndex; i++) { if (activeLoaders.ContainsKey(i)) continue; var item = ui.sc_list.GetChildAt(i) as item_scalnums; if (item == null) continue; if (item.com_pic.picture != null && !item.com_pic.picture.isDisposed) GLoaderPool.Instance.ReturnLoader(item.com_pic.picture); var loader = GLoaderPool.Instance.GetLoader(); item.com_pic.picture = loader; item.com_pic.AddChild(loader); loader.SetSize(item.com_pic.width, item.com_pic.height); _fileIsExist.TryGetValue(i, out var value); if (!value) { var localPath = Path.Combine(TextureHelper.getResPath(), _secretData[i].Name + ".jpg"); if (File.Exists(localPath)) { _fileIsExist[i] = true; Debug.Log($"[SetImgLoader] 本地存在,直接加载 {_secretData[i].Name}"); CrazyAsyKit.StartCoroutine(TextureHelper.LoadTexture(_secretData[i].Name, loader, null, "SecretAlbums/")); } else { _fileIsExist[i] = false; } } else { CrazyAsyKit.StartCoroutine(TextureHelper.LoadTexture(_secretData[i].Name, loader, null, "SecretAlbums/")); } activeLoaders[i] = loader; } // Debug.Log($"[ScrollUpdate] active loaders={activeLoaders.Count}, pool={GLoaderPool.Instance.GetPoolCount()}, inUse={GLoaderPool.Instance.GetInUseCount()}"); } private void OnScrollEnd() { if (_secretData == null || _secretData.Count == 0) return; var firstVisibleIndex = ui.sc_list.GetFirstChildInView(); var lastVisibleIndex = Mathf.Min(firstVisibleIndex + MaxVisibleCount - 1, ui.sc_list.numItems - 1); var startIndex = Mathf.Max(0, firstVisibleIndex - PreloadCount); var endIndex = Mathf.Min(ui.sc_list.numItems - 1, lastVisibleIndex + PreloadCount); // Debug.Log($"[ScrollEnd] start index={startIndex} end index={endIndex}"); var tasks = new List<(GLoader loader, string fileName, Action callback, string folder, string localFolder)>(); // 分配 loader 并加载图片 for (var i = startIndex; i <= endIndex; i++) { _fileIsExist.TryGetValue(i, out var value); if (value) continue; var item = ui.sc_list.GetChildAt(i) as item_scalnums; if (item == null) continue; if (item.com_pic.picture != null && !item.com_pic.picture.isDisposed) GLoaderPool.Instance.ReturnLoader(item.com_pic.picture); var loader = GLoaderPool.Instance.GetLoader(); item.com_pic.picture = loader; item.com_pic.AddChild(loader); loader.SetSize(item.com_pic.width, item.com_pic.height); var idx = i; tasks.Add((loader, _secretData[i].Name, texture => { if (texture != null) _fileIsExist[idx] = true; }, "SecretAlbums/", FolderNames.SecretName)); activeLoaders[i] = loader; } if (tasks.Count > 0) { TextureHelper.SetImgLoaders(tasks); } } private void ItemRender(int index, GObject obj) { var item = (item_scalnums)obj; item.text_id.text = _secretData[index].id.ToString(); var isUnlock = DataMgr.SecretUnlockList.Value.Contains(index); item.btn_unlock.pay_type.selectedIndex = _secretData[index].PayType; if (_secretData[index].PayType == 0) item.btn_unlock.title = GameHelper.getPrice((decimal)_secretData[index].DiscountPrice); else if (_secretData[index].PayType == 1) item.btn_unlock.title = _secretData[index].GoldCoins.ToString(); else if (_secretData[index].PayType == 2) item.btn_unlock.title = _secretData[index].AD + "AD"; if (isUnlock) { item.btn_unlock.pay_type.selectedIndex = 3; if (_secretData[index].SubscribeUnlock == 1) { item.vip.selectedIndex = 2; item.btn_unlock.pay_type.selectedIndex = 4; } item.btn_unlock.title = "GO"; } else { if (_secretData[index].SubscribeUnlock == 1) { item.vip.selectedIndex = 1; item.btn_unlock.pay_type.selectedIndex = 4; } } item.btn_null.SetClick(GotoNext); item.un_lock.selectedIndex = isUnlock ? 1 : 0; item.btn_unlock.SetClick(GotoNext); item.peple_num.text = GetPepleNum(_secretData[index].Quantity).ToString(); item.hot.selectedIndex = _secretData[index].HotType; void GotoNext() { var da = _secretData; var data = new AlbumPreviewData { Index = index, State = _secretData[index].State, Price = _secretData[index].Price, PayType = _secretData[index].PayType, SubscribeUnlock = _secretData[index].SubscribeUnlock, DiscountPrice = _secretData[index].DiscountPrice, Name = _secretData[index].Name, Name2 = _secretData[index].Name2, GoldCoins = _secretData[index].GoldCoins, AD = _secretData[index].AD, CD = _secretData[index].CD }; UICtrlDispatcher.Instance.Dispatch(UICtrlMsg.SecretAlbumsNextUI_Open, data); } } private int GetPepleNum(float quantity) { // 获取当前时间 DateTime now = DateTime.Now; // 计算当天已经过去的分钟数(从凌晨 0 点开始算) int minutesPassedToday = now.Hour * 60 + now.Minute; // 计算人数 int num = Mathf.FloorToInt(quantity * minutesPassedToday); return num; } } public class AlbumPreviewData { public int[] State; public int Index; public string Name; public float Price; public int SubscribeUnlock; public int PayType; public float DiscountPrice; public string Name2; public int GoldCoins; public int AD; public int CD; } public enum UnlockPayType { Pay = 0, Coin = 1, Ad = 2, None = 3, } }