// 文件位置: Assets/Scripts/TH1_UI/Controller/Base/ViewController.cs // (请确保命名空间和你的项目一致) using System; using System.Collections.Generic; using TH1_UI; using TH1_UI.Core; using TH1_UI.View.Base; using UnityEngine; // 这是你原有的代码,为了完整性我把它折叠起来了,无需修改 #region Unchanged Interfaces and Usings namespace TH1_UI.Controller.Base { public interface IViewControllerInterface { ViewDestroyDomain Domain { get; } ViewLevelValue ViewLevel { get; } ViewDepthProperty DepthProperty { get; } ViewOpenProperty OpenProperty { get; } ViewCloseProperty CloseProperty { get; } ViewLoadProperty LoadProperty { get; } string Name { get; } int Depth { get; set; } void Start(string subFolderPath, string resourceName, ViewDestroyDomain domain); bool Open(); bool IsShow(); bool OpenWithParam(string param); bool Close(); void Destroy(); } #endregion public class ViewController : IViewControllerInterface where T : View.Base.View { // ... (这里到 _TryOpen 之前的所有代码都保持原样,无需改动) ... public ViewDestroyDomain Domain => _domain; public ViewDepthProperty DepthProperty => _depthProperty; public ViewCloseProperty CloseProperty { get; } = new ViewCloseProperty(); public ViewOpenProperty OpenProperty { get; } = new ViewOpenProperty(); public ViewLoadProperty LoadProperty => _loadProperty; protected ViewHierarchyProperty HierarchyProperty { get; } = new ViewHierarchyProperty(); protected ViewCameraProperty CameraProperty { get; } = new ViewCameraProperty(); protected ViewMaskProperty MaskProperty { get; } = new ViewMaskProperty(); public ViewLevelValue ViewLevel => HierarchyProperty.ViewLevel; public string Name => _loadProperty.ControllerName; public int Depth { get => _depthProperty.Depth; set { if (IsShow()) { _script.SetSortingOrder(value); } } } public T WindowScript => _script; public GameObject WindowObj => _windowObj; protected void AddLoadAtlas(string name) { UIResourceController.Instance.AddAtlasHolder(name, LoadProperty.ControllerName); if (!_atlasLoadList.Contains(name)) { _atlasLoadList.Add(name); } } public virtual void Start(string subFolderPath, string resourceName, ViewDestroyDomain domain) { _domain = domain; LoadProperty.SubFolderPath = subFolderPath; LoadProperty.ResourceName = resourceName; LoadProperty.ControllerName = this.GetType().Name; DepthProperty.Start(this); HierarchyProperty.Start(this); CameraProperty.ThisController = this; } public virtual bool Open() { _atlasPreloadingValue.Clear(); if (EnableOpen()) { _TryOpen(); return true; } else { return false; } } public virtual bool OpenWithParam(string param) { return Open(); } protected virtual bool EnableOpen() { return true; } bool _TryOpen() { if (IsShow()) { UpdateView(); return false; } bool preLoadWait = _PreLoad(); if (preLoadWait) { _atlasPreloadingValue.Add("PreLoad", 30, true); } if (WindowObj == null) { // ✅ 核心修改 #1: 使用新的 GetWindow 方法签名 // 现在的 GetWindow 只负责查找,Key 使用 ResourceName GameObject window = UIResourceController.Instance.GetWindow(LoadProperty.ResourceName); if (window == null) { // 如果找不到,就启动我们改造后的 ViewLoadProperty 去加载 if (LoadProperty.LoadState == LoadWindowState.NONE) { LoadProperty.Attach(_loadViewCallback, _OnViewLoadedCallback); LoadProperty.Start(); } } else { // 如果找到了,说明是之前加载过的,直接开始后续流程 LoadProperty.Invoke(); _OnWindowLoadNotify(window); _OnViewStart(); } } else { _OnViewStart(); } return true; } protected virtual bool _PreLoad() { _PreLoadSubViewController(); return UIResourceController.Instance.LoadAtlasList(_atlasLoadList, _OnCompletePreLoad); } void _OnCompletePreLoad() { if (_atlasPreloadingValue.Has("PreLoad")) { _atlasPreloadingValue.Del("PreLoad"); _OnViewStart(); } } void _OnViewLoadedCallback(UInt32 eveID) { // ✅ 核心修改 #2: 在异步(现在是同步)回调中,同样使用新的 GetWindow 方法 GameObject window = UIResourceController.Instance.GetWindow(LoadProperty.ResourceName); _OnWindowLoadNotify(window); _OnViewStart(); } void _OnWindowLoadNotify(System.Object obj) { _windowObj = obj as GameObject; if (_windowObj == null) { // 为了兼容性,暂时注释掉需要ViDebuger的代码 // ViDebuger.Error("Window GameObject is NULL! [res: " + LoadProperty.ResourceName + "]"); Debug.LogError("Window GameObject is NULL! [res: " + LoadProperty.ResourceName + "]"); return; } UIWindowProperty propertyScript = _windowObj?.GetComponentInChildren(); if (propertyScript == null) { // ViDebuger.Error(WindowObj.name + " Script is null, Then Initializtion error!"); Debug.LogError(WindowObj.name + " Script is null, Then Initializtion error!"); } _script = _windowObj?.GetComponent(); if (_script == null) { _script = _windowObj?.AddComponent(); } _script?.Initialize(propertyScript); OnLoaded(); _LoadSubViewController(_windowObj); } void _OnViewStart() { if (WindowObj != null && WindowScript != null && !_atlasPreloadingValue.Value) { _OnOpenWindowNotify(WindowObj); } } void _OnOpenWindowNotify(System.Object obj) { _TrueOpen(); } void _TrueOpen() { if (_script != null) { _script.SetEnableClick(MaskProperty.EnableClick); _script.Show(); } DepthProperty.Open(); RegisterEventCallback(); OpenProperty.Execute(); HierarchyProperty.Open(); CameraProperty.Open(); OnOpen(); _OpenSubViewController(); OnOpenSub(); } public virtual bool Close() { _loadViewCallback.End(); _atlasPreloadingValue.Clear(); if (IsShow()) { _ReleasePreLoad(); _TrueClose(); return true; } else { _atlasLoadList.Clear(); if (LoadProperty.LoadState == LoadWindowState.LOADING) { _loadViewCallback.End(); LoadProperty.LoadState = LoadWindowState.NONE; } else if (LoadProperty.LoadState == LoadWindowState.LOADED) { _loadViewCallback.End(); } return true; } } void _TrueClose() { UnregisterEventCallback(); OnClose(); _CloseSubViewController(); DepthProperty.Close(); CameraProperty.Close(); if (_script != null) { _script.Hide(); } HierarchyProperty.Close(); CloseProperty.Execute(); } protected bool _ReleasePreLoad() { for (int iter = 0; iter < _atlasLoadList.Count; ++iter) { string iterAtlas = _atlasLoadList[iter]; if (UIResourceController.Instance.DelAtlasHolder(iterAtlas, LoadProperty.ControllerName)) { UIResourceController.Instance.ReleaseAtlas(iterAtlas); } } _atlasLoadList.Clear(); return true; } public virtual void Destroy() { Close(); _ReleasePreLoad(); _DestroySubViewController(); // ✅ 核心修改 #3: 删除窗口时,使用的key必须和获取/添加窗口时一致,即 ResourceName UIResourceController.Instance.DelWindow(LoadProperty.ResourceName); if (_windowObj != null) { // GameObject.Destroy() 已经是 UIResourceController.DelWindow 的一部分了 // 所以这里不需要再 Destroy,只需要将引用置空 _windowObj = null; } _script = null; LoadProperty.End(); } public virtual bool IsShow() { if (_script == null) { return false; } return _script.IsShow(); } // ... (这里往后的代码,包括子界面管理等,都保持原样,无需改动) ... protected virtual void OnLoaded() { } protected virtual void OnOpen() { } protected virtual void OnOpenSub() { } protected virtual void RegisterEventCallback() { } protected virtual void UnregisterEventCallback() { } protected virtual void OnClose() { } protected virtual void UpdateView() { } T _script; ViewDestroyDomain _domain; GameObject _windowObj; ViAsynCallback _loadViewCallback = new ViAsynCallback(); // 这是一个未知类型,但我们无需修改 ViewDepthProperty _depthProperty = new ViewDepthProperty(); ViewLoadProperty _loadProperty = new ViewLoadProperty(); ViPriorityValue _atlasPreloadingValue = new ViPriorityValue(false); // 这是一个未知类型,但我们无需修改 List _atlasLoadList = new List(); Dictionary _subViewDict = new Dictionary(); protected T1 AddSubViewController(string childPath, string ex = null) where T1 : ViewControllerSubInterface, new() { var sub = new T1(); sub.Start(childPath, this); _subViewDict.Add(typeof(T1).Name + ex, sub); return sub; } public T1 GetSubViewController(string ex = null) where T1 : ViewControllerSubInterface, new() { _subViewDict.TryGetValue(typeof(T1).Name + ex, out var subViewController); return (T1) subViewController; } void _PreLoadSubViewController() { foreach (var kv in _subViewDict) { var subViewController = kv.Value; subViewController.PreLoad(); var loadAtlas = subViewController.GetLoadAtlas(); foreach (var atlas in loadAtlas) { AddLoadAtlas(atlas); } } } void _LoadSubViewController(GameObject windowObj) { foreach (var kv in _subViewDict) { kv.Value.OnWindowLoadNotify(windowObj); } } void _OpenSubViewController() { foreach (var kv in _subViewDict) { if (kv.Value.DefaultOpen) { kv.Value.Open(); } } } void _CloseSubViewController() { foreach (var kv in _subViewDict) { kv.Value.Close(); } } void _DestroySubViewController() { foreach (var kv in _subViewDict) { kv.Value.Destroy(); } } protected void CloseAllSubView() { foreach (var kv in _subViewDict) { kv.Value.Close(); } } } }