using System; using System.Collections.Generic; using System.IO; using System.Linq; using DG.Tweening; using FairyGUI; using FGUI.LG_albums; using UnityEngine; using System; using System.Threading; using System.Threading.Tasks; namespace RedHotRoast { public class AlubumUI : BaseUI { private AlubumUICtrl ctrl; private AlubumModel model; private com_albums ui; private long[] UpDatatime; public AlubumUI(AlubumUICtrl ctrl) : base(ctrl) { uiName = UIConst.AlubumUI; this.ctrl = ctrl; } protected override void SetUIInfo(UIInfo uiInfo) { uiInfo.packageName = "LG_albums"; uiInfo.assetName = "com_albums"; uiInfo.layerType = UILayerType.Popup; uiInfo.isNeedOpenAnim = false; uiInfo.isNeedCloseAnim = false; uiInfo.isNeedUIMask = true; } //初始化页面逻辑 private void InitView(object a = null) { UpDatatime = new long[LevelData.Count]; ImageName = new string[LevelData.Count]; ui.list_albums.itemRenderer = RendererList; ui.list_albums.numItems = LevelData.Count; InitScroll(); } private void SetItemData(object obj = null) { UpDatatime[(int)obj] = 0; ui.list_albums.RefreshVirtualList(); } #region 生命周期 protected override void OnInit() { GLoaderPool.Instance.Init(null, 24, 312, 310); } protected override void OnClose() { foreach (var t in loader_list) if (t != null && !t.isDisposed && t.texture != null) { t.texture.Dispose(); t.texture = null; } // 1. 解除 UI 对 Loader 的引用 for (var i = 0; i < ui.list_albums.numChildren; i++) { var item = ui.list_albums.GetChildAt(i) as item_albums; if (item != null && item.com_loader.loader != null) item.com_loader.loader = null; // 清掉 GLoader 引用 } activeLoaders.Clear(); _fileIsExist.Clear(); GLoaderPool.Instance.DisposeAll(); TextureHelper.ClearMaterialPool(); // 强制卸载未使用的资源 Resources.UnloadUnusedAssets(); MemoryManager.CleanMemoryMonitor(); } protected override void OnBind() { ui = baseUI as com_albums; } private List LevelData; private readonly List loader_list = new(); public SmartInvoker invoker; protected override void OnOpenBefore(object args) { invoker = new SmartInvoker(() => { for (int i = 0; i < UpDatatime.Length; i++) { UpDatatime[i] = 0; // ImageName[i] = ""; } ui.list_albums.RefreshVirtualList(); }, TimeSpan.FromSeconds(0.2f)); LevelData = ConfigSystem.GetConfig(); ui.list_albums.SetVirtual(); ui.btn_close1.SetClick(() => { CtrlCloseUI(); }); InitView(); } private const int MaxVisibleCount = 18; // 一屏显示18个 private const int PreloadCount = 3; // 上下各预加载一屏 private readonly Dictionary activeLoaders = new(); private readonly Dictionary _fileIsExist = new(); private Throttle _throttle; private void InitScroll() { // ui.list_albums.scrollPane.onScroll.Add(OnScrollUpdate); ui.list_albums.scrollPane.onScrollEnd.Add(OnScrollEndCB); // 保留结束时的整理 OnScrollEnd(); } private void OnScrollEndCB() { // UpdateVisibleAndPreload(); OnScrollEnd(); // Debug.Log("更新一次"); } private void UpdateVisibleAndPreload() { // Debug.Log("[UpdateVisibleAndPreload]--------111111--------- "); // if (LevelData == null || LevelData.Count == 0) return; // var firstVisibleIndex = ui.list_albums.GetFirstChildInView(); // var lastVisibleIndex = Mathf.Min(firstVisibleIndex + MaxVisibleCount - 1, ui.list_albums.numItems - 1); // var startIndex = Mathf.Max(0, firstVisibleIndex - PreloadCount); // var endIndex = Mathf.Min(ui.list_albums.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.list_albums.GetChildAt(idx) as item_albums; // if (oldItem != null) oldItem.com_loader.loader = 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.list_albums.GetChildAt(i) as item_albums; // if (item == null) continue; // if (item.com_loader.loader != null && !item.com_loader.loader.isDisposed) // GLoaderPool.Instance.ReturnLoader(item.com_loader.loader); // var loader = GLoaderPool.Instance.GetLoader(); // item.com_loader.loader = loader; // item.com_loader.AddChild(loader); // loader.SetSize(item.com_loader.loader.width, item.com_loader.loader.height); // _fileIsExist.TryGetValue(i, out var value); // if (!value) // { // var localPath = Path.Combine(TextureHelper.getResPath(), LevelData[i].Name + ".jpg"); // if (File.Exists(localPath)) // { // _fileIsExist[i] = true; // Debug.Log($"[SetImgLoader] 本地存在,直接加载 {LevelData[i].Name}"); // CrazyAsyKit.StartCoroutine(TextureHelper.LoadTexture(LevelData[i].Name, loader, null, // "LevelAlbums/")); // } // else // { // _fileIsExist[i] = false; // } // } // else // { // CrazyAsyKit.StartCoroutine(TextureHelper.LoadTexture(LevelData[i].Name, loader, null, // "LevelAlbums/")); // } // activeLoaders[i] = loader; // } // Debug.Log($"[ScrollUpdate] active loaders={activeLoaders.Count}, pool={GLoaderPool.Instance.GetPoolCount()}, inUse={GLoaderPool.Instance.GetInUseCount()}"); } private void OnScrollEnd() { invoker.Invoke(); // for (int i = 0; i < UpDatatime.Length; i++) // { // UpDatatime[i] = 0; // // ImageName[i] = ""; // } // DOVirtual.DelayedCall(0.1f, () => // { // ui.list_albums.RefreshVirtualList(); // }); // if (LevelData == null || LevelData.Count == 0) return; // var firstVisibleIndex = ui.list_albums.GetFirstChildInView(); // var lastVisibleIndex = Mathf.Min(firstVisibleIndex + MaxVisibleCount - 1, ui.list_albums.numItems - 1); // var startIndex = Mathf.Max(0, firstVisibleIndex - PreloadCount); // var endIndex = Mathf.Min(ui.list_albums.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)>(); // // 分配 loader 并加载图片 // for (var i = startIndex; i <= endIndex; i++) // { // _fileIsExist.TryGetValue(i, out var value); // if (value) continue; // if (GameHelper.GetLevel() < i + 1) continue; // var item = ui.list_albums.GetChildAt(i) as item_albums; // if (item == null) continue; // if (item.com_loader.loader != null && !item.com_loader.loader.isDisposed) // GLoaderPool.Instance.ReturnLoader(item.com_loader.loader); // var loader = GLoaderPool.Instance.GetLoader(); // item.com_loader.loader = loader; // item.com_loader.AddChild(loader); // loader.SetSize(item.com_loader.loader.width, item.com_loader.loader.height); // var idx = i; // tasks.Add((loader, LevelData[i].Name, NTexture => // { // if (NTexture != null) _fileIsExist[idx] = true; // }, "LevelAlbums/")); // activeLoaders[i] = loader; // } // if (tasks.Count > 0) TextureHelper.SetImgLoaders(tasks); } private string[] ImageName; private void RendererList(int index, GObject obj) { // Debug.Log("Render list" ); // Debug.Log(JsonConvert.SerializeObject(LevelData[index])); item_albums item = (item_albums)obj; item.text_num.text = (index + 1).ToString(); if (index < GameHelper.GetCommonModel().MultiModal - 1) { item.type_.selectedIndex = 0; if (GameHelper.GetLevel() > index + 1) { item.SetClick(() => { uiCtrlDispatcher.Dispatch(UICtrlMsg.AlbumDetailUI_Open, index); }); } else { item.SetClick(() => { GameHelper.ShowTips("lv_unlock", true); }); } } else { Levelunlock levelunlock_ = DataMgr.LevelUnlockListNew.Value.FirstOrDefault(x => x.level_ == index + 1); if (levelunlock_ != null) { item.type_.selectedIndex = levelunlock_.type; } else item.type_.selectedIndex = 0; if (GameHelper.GetLevel() > index + 1) { item.SetClick(() => { uiCtrlDispatcher.Dispatch(UICtrlMsg.AlbumDetailUI_Open, index); }); } else { item.SetClick(() => { GameHelper.ShowTips("lv_unlock", true); }); } } if (GameHelper.GetNowTime() < UpDatatime[index] + 1) return; UpDatatime[index] = GameHelper.GetNowTime(); // if (!activeLoaders.ContainsValue(item.com_loader.loader)) activeLoaders[index] = item.com_loader.loader; if (!loader_list.Contains(item.com_loader.GetChild("loader") as GLoader)) loader_list.Add(item.com_loader.GetChild("loader") as GLoader); if (index < GameHelper.GetCommonModel().MultiModal - 1) { if (GameHelper.GetLevel() > index + 1) { item.isUnlock.selectedIndex = 1; if (item.com_loader.loader.texture == null || item.com_loader.loader.texture.nativeTexture.name != LevelData[index].Name) { // item.isUnlock.selectedIndex = 0; // if (item.com_loader.loader.texture != null) // { // item.com_loader.loader.texture.Dispose(); // 释放 GPU 资源 // item.com_loader.loader.texture = null; // 断开引用 // } TextureHelper.SetImgLoader(item.com_loader.GetChild("loader") as GLoader, LevelData[index].Name, (a) => { Debug.Log(item.com_loader.loader.texture.nativeTexture.name); }, "LevelAlbums/", FolderNames.AlbumName); ImageName[index] = LevelData[index].Name; } item.touchable = true; } else { item.isUnlock.selectedIndex = 0; // item.touchable = false; } } else { Levelunlock levelunlock_ = DataMgr.LevelUnlockListNew.Value.FirstOrDefault(x => x.level_ == index + 1); if (GameHelper.GetLevel() > index + 1) { if (levelunlock_ != null) { item.isUnlock.selectedIndex = 1; if (item.com_loader.loader.texture == null || item.com_loader.loader.texture.nativeTexture.name != ImageName[index]) { if (levelunlock_.type == 0) { if (levelunlock_.config_index >= ConfigSystem.GetConfig().Count) levelunlock_.config_index = ConfigSystem.GetConfig().Count - 1; FreeImageLibrary _leveldata = ConfigSystem.GetConfig()[levelunlock_.config_index]; TextureHelper.SetImgLoader(item.com_loader.GetChild("loader") as GLoader, _leveldata.Name, null, "LevelAlbums/", FolderNames.AlbumName); ImageName[index] = LevelData[index].Name; } else if (levelunlock_.type == 1) { if (levelunlock_.config_index >= ConfigSystem.GetConfig().Count) levelunlock_.config_index = ConfigSystem.GetConfig().Count - 1; ADImageLibrary _leveldata = ConfigSystem.GetConfig()[levelunlock_.config_index]; TextureHelper.SetImgLoader(item.com_loader.GetChild("loader") as GLoader, _leveldata.Name, null, "LevelAlbums/", FolderNames.AlbumName); ImageName[index] = LevelData[index].Name; } else if (levelunlock_.type == 2) { if (levelunlock_.config_index >= ConfigSystem.GetConfig().Count) levelunlock_.config_index = ConfigSystem.GetConfig().Count - 1; SpecialImageLibrary _leveldata = ConfigSystem.GetConfig()[levelunlock_.config_index]; TextureHelper.SetImgLoader(item.com_loader.GetChild("loader") as GLoader, _leveldata.Name, null, "LevelAlbums/", FolderNames.AlbumName); ImageName[index] = LevelData[index].Name; } else if (levelunlock_.type == 3) { if (levelunlock_.config_index >= ConfigSystem.GetConfig().Count) levelunlock_.config_index = ConfigSystem.GetConfig().Count - 1; VIPImageLibrary _leveldata = ConfigSystem.GetConfig()[levelunlock_.config_index]; TextureHelper.SetImgLoader(item.com_loader.GetChild("loader") as GLoader, _leveldata.Name, null, "LevelAlbums/", FolderNames.AlbumName); ImageName[index] = LevelData[index].Name; } } } else { item.isUnlock.selectedIndex = 1; if (item.com_loader.loader.texture == null || item.com_loader.loader.texture.nativeTexture.name != LevelData[index].Name) { TextureHelper.SetImgLoader(item.com_loader.GetChild("loader") as GLoader, LevelData[index].Name, null, "LevelAlbums/", FolderNames.AlbumName); ImageName[index] = LevelData[index].Name; } } } else { // item.touchable = false; item.isUnlock.selectedIndex = 0; } } } 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.UnlockAlbums, SetItemData); } protected override void RemoveListener() { GameDispatcher.Instance.RemoveListener(GameMsg.UnlockAlbums, SetItemData); } #endregion } public class SmartInvoker { private readonly Action _action; private readonly TimeSpan _delay; private DateTime _lastImmediateInvoke = DateTime.MinValue; private CancellationTokenSource _cts = null; private readonly object _lock = new object(); private bool _hasPending = false; public SmartInvoker(Action action, TimeSpan delay) { _action = action; _delay = delay; } public void Invoke() { lock (_lock) { var now = DateTime.UtcNow; var timeSinceLast = now - _lastImmediateInvoke; if (timeSinceLast >= _delay) { _lastImmediateInvoke = now; _action(); Debug.Log("diaoyongyiciiiiiiiiiiiiiii"); } else { _hasPending = true; _cts?.Cancel(); _cts = new CancellationTokenSource(); var token = _cts.Token; Task.Delay(_delay, token).ContinueWith(t => { if (!t.IsCanceled) { lock (_lock) { if (_hasPending) { _lastImmediateInvoke = DateTime.UtcNow; _hasPending = false; _action(); Debug.Log("diaoyongyiciiiiiiiiiiiiiii"); } } } }, TaskScheduler.Default); } } } } }