using System.Collections.Generic; using FairyGUI; using FGUI.LG_live; using SGModule.Common.Extensions; using UnityEngine; using UnityEngine.Video; namespace BallKingdomCrush { public class LiveUI : BaseUI { private const int MaxVisibleCount = 6; // 一屏最多6个播放器 private static readonly Dictionary dictionary_ = new(); private LiveUICtrl ctrl; private float late_time = 0.1f; private List LiveConfig; private LiveModel model; private com_live ui; private GameObject videoParent; public LiveUI(LiveUICtrl ctrl) : base(ctrl) { uiName = UIConst.LiveUI; this.ctrl = ctrl; } protected override void SetUIInfo(UIInfo uiInfo) { uiInfo.packageName = "LG_live"; uiInfo.assetName = "com_live"; uiInfo.layerType = UILayerType.Popup; uiInfo.isNeedOpenAnim = false; uiInfo.isNeedCloseAnim = false; uiInfo.isNeedUIMask = true; } private void UpdateEvent() { late_time = 0.1f; } // 初始化页面逻辑 private void InitView() { } #region 生命周期 protected override void OnInit() { videoParent = new GameObject("VideoPlayerParent"); VideoPlayerPool.Instance.Init(videoParent, MaxVisibleCount); } protected override void OnClose() { // 归还所有播放器 foreach (var kvp in dictionary_) VideoPlayerPool.Instance.ReturnPlayer(kvp.Value); dictionary_.Clear(); VideoPlayerPool.Instance.DisposeAll(); Object.Destroy(videoParent); foreach (var t in loader_list) if (t != null && !t.isDisposed && t.texture != null) { t.texture.Dispose(); t.texture = null; } GLoaderPool.Instance.DisposeAll(); TextureHelper.ClearMaterialPool(); // 强制卸载未使用的资源 // Resources.UnloadUnusedAssets(); // MemoryManager.CleanMemoryMonitor(); } protected override void OnBind() { ui = baseUI as com_live; } private readonly List loader_list = new(); protected override void OnOpenBefore(object args) { LiveConfig = ConfigSystem.GetLiveConfig(); ui.list_.itemRenderer = RendererList; Debug.Log($"LiveConfig.Count==1=== {LiveConfig.Count}"); ui.list_.numItems = LiveConfig.Count; ui.btn_close.SetClick(() => { CtrlCloseUI(); }); InitView(); // 滚动过程中实时刷新可见播放器 ui.list_.scrollPane.onScrollEnd.Add(OnScrollEnd); // 打开页面时初始化一次 OnScrollEnd(); } private HashSet lastVisibleItems = new(); private void OnScrollEnd() { Debug.Log($"[OnScrollEnd]==lastVisibleItems=== {lastVisibleItems.Count}"); // 1️⃣ 回收上一次的可见播放器 foreach (var oldItem in lastVisibleItems) if (dictionary_.TryGetValue(oldItem, out var player)) { player.Pause(); player.targetTexture?.Release(); VideoPlayerPool.Instance.ReturnPlayer(player); dictionary_.Remove(oldItem); oldItem.com_loader.visible = false; oldItem.img_cover.visible = true; } lastVisibleItems.Clear(); // 2️⃣ 获取当前可见项 var firstIndex = ui.list_.GetFirstChildInView(); var lastIndex = Mathf.Min(firstIndex + MaxVisibleCount, ui.list_.numItems); HashSet newVisibleItems = new(); for (var i = firstIndex; i < lastIndex; i++) if (ui.list_.GetChildAt(i) is item_live item) { newVisibleItems.Add(item); // 分配播放器 if (!dictionary_.ContainsKey(item)) { var player = VideoPlayerPool.Instance.GetPlayer(); if (player != null) { dictionary_[item] = player; BindPlayerToItem(item, i); } } } // 3️⃣ 保存为“上一次可见项” lastVisibleItems = newVisibleItems; } private void BindPlayerToItem(item_live item, int index) { var data = PreDownloadManager.GetLiveDataByIndex(LiveConfig[index], index); Debug.Log($"[绑定播放器 进度] progress==1=== {data.progress}"); if (data.progress <= 0) return; var player = dictionary_[item]; var loader = item.com_loader.GetChild("loader") as GLoader; item.com_loader.visible = true; if (!loader_list.Contains(loader)) loader_list.Add(loader); TextureHelper.SetVideoLoader(player, loader, LiveConfig[index].Name, vp => { if (vp != null && !item.isDisposed) { if (data.progress >= 100) { item.img_cover.visible = false; GameDispatcher.Instance.Dispatch(GameMsg.liveVideoLoaded); } } }); } private void RendererList(int index, GObject obj) { var livedata_ = PreDownloadManager.GetLiveDataByIndex(LiveConfig[index], index); var item = (item_live)obj; // UI状态显示 item.state.selectedIndex = livedata_.progress <= 0 ? 1 : 0; if (LiveConfig[index].SubscribeUnlock == 1) { if (livedata_.progress < 100) item.vip.selectedIndex = 1; else item.vip.selectedIndex = 2; } else item.vip.selectedIndex = 0; item.mask.img_mask.fillAmount = (float)(100 - livedata_.progress) / 100; var coverLoader = item.img_cover.GetChild("loader") as GLoader; LiveVideoManager.Instance.GetVideoCover(coverLoader, LiveConfig[index].Name + "_cover", (tex) => { if (tex != null) { if (coverLoader != null) { coverLoader.texture = new NTexture(tex); coverLoader.visible = true; } } }); // 点击事件 item.SetClick(() => { if (GameHelper.GetLevel() < GameHelper.GetCommonModel().UnlockLive[1]) { if (DataMgr.IsUnlockLive.Value < 0 && DataMgr.VipLevel.Value < 0) UICtrlDispatcher.Instance.Dispatch(UICtrlMsg.SecretUnlockUI_Open, 2); else if (DataMgr.IsUnlockLive.Value == 0) UICtrlDispatcher.Instance.Dispatch(UICtrlMsg.UnlockTipsUI_Open, 2); else HandleDetailOpen(item, index); } else { HandleDetailOpen(item, index); } }); } private void HandleDetailOpen(item_live item, int index) { if (dictionary_.TryGetValue(item, out var player)) uiCtrlDispatcher.Dispatch(UICtrlMsg.LiveDetailUI_Open, (index, player)); } 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.LiveChange, Refresh); HallManager.Instance.UpdateEvent += UpdateEvent; } protected override void RemoveListener() { GameDispatcher.Instance.RemoveListener(GameMsg.LiveChange, Refresh); HallManager.Instance.UpdateEvent -= UpdateEvent; } private void Refresh(object param = null) { var index = param.As(); // ui.list_.itemRenderer = RendererList; // Debug.Log($"LiveConfig.Count==2=== {LiveConfig.Count}"); // ui.list_.numItems = LiveConfig.Count; if (ui.list_.GetChildAt(index) is item_live item) { item.state.selectedIndex = 0; var livedata_ = PreDownloadManager.GetLiveDataByIndex(LiveConfig[index], index); item.mask.img_mask.fillAmount = (float)(100 - livedata_.progress) / 100; BindPlayerToItem(item, index); if (LiveConfig[index].SubscribeUnlock == 1) { if (livedata_.progress < 100) item.vip.selectedIndex = 1; else item.vip.selectedIndex = 2; } else item.vip.selectedIndex = 0; } } #endregion } public class LiveData { public int AD_num; public int progress; public int Singleprogress; public long LiveADTime; } }