using System; using System.Collections.Generic; using UnityEngine; using XGame.Framework.Asset; using XGame.Framework.Asyncs; using XGame.Framework.Interfaces; namespace XGame.Framework.UI { public class UIModule : IUIModule, IUpdate, ILateUpdate, IUIContextSetter, IDisposable, IUIAssetModuleCreator { private UIContext _context; private IUITree _uitree; private IAssetModule _assetModule; /// /// 加载中的 /// private Dictionary _loadingMap; /// /// 已打开的UI /// private Dictionary _openedMap; /// /// 已关闭的UI /// private Dictionary _closedMap; /// /// Update 和 LateUpdate用 /// private List _updates; public UIModule(IAssetModule assetModule, IUITree uitree) { _assetModule = assetModule; _uitree = uitree; _loadingMap = new Dictionary(); _openedMap = new Dictionary(); _closedMap = new Dictionary(); _updates = new List(); } public UIContext Context { get => _context; set => _context = value; } #region 接口实现 Camera IUIModule.Camera => _uitree.Camera; Canvas IUIModule.GetCanvas(UILayer layer) { return _uitree.GetCanvas(layer); } IAsync IUIModule.OpenAsync(UIKey uikey, object intent) { string key = uikey; if (_loadingMap.ContainsKey(key)) { return _loadingMap[key]; } var asyncGroup = new AsyncGroup(); if (_openedMap.ContainsKey(key)) { Log.Warn($"重复开启UI:{key}"); } else if (_closedMap.TryGetValue(key, out var closedView)) { // 已关闭的UI asyncGroup.On(_ => { _closedMap.Remove(key); _uitree.SetAsLastSibling(closedView.Panel); closedView.Enable(intent); _openedMap.Add(key, closedView); }); } else { _loadingMap.Add(key, asyncGroup); var loadAsync = _assetModule.LoadAsync(key); loadAsync.Join(asyncGroup); loadAsync.On(_ => { _loadingMap.Remove(key); var panel = loadAsync.Result; if (panel == null) { Log.Error($"UI加载结果为空. UIKey:{key}"); return; } var view = Activator.CreateInstance(uikey.UIViewType) as IUIView; var context = _context.Clone(); (context as IUIViewAdapter).Key = uikey; (view as UIView).Init(context, panel); _uitree.AddPanel(panel); view.Enable(intent); _openedMap.Add(key, view); }); } asyncGroup.End(); return asyncGroup; } void IUIModule.Close(UIKey uikey, bool isDestroy) { var key = uikey.Key; if (_loadingMap.TryGetValue(key, out var async)) { _loadingMap.Remove(key); async.RemoveAll(); return; } if (_openedMap.TryGetValue(key, out var uiView)) { _openedMap.Remove(key); uiView.Disable(); if (isDestroy) { DestroyUIView(uiView); } else { _closedMap.Add(key, uiView); } return; } if (isDestroy && _closedMap.TryGetValue(key, out uiView)) { _closedMap.Remove(key); DestroyUIView(uiView); } } IAsync IUIModule.Preload(UIKey uikey) { var loadAsync = _assetModule.PreloadAsync(uikey); return loadAsync; } bool IUIModule.IsOpened(UIKey uikey) { return _openedMap.ContainsKey(uikey); } void IUpdate.Update(int millisecond) { if (_openedMap.Count == 0) return; _updates.Clear(); _updates.AddRange(_openedMap.Values); for(var i = 0; i < _updates.Count;) { var view = _updates[i]; view.Update(millisecond); if (view.Active) { i++; } else { _updates.RemoveAt(i); } } } void ILateUpdate.LateUpdate(int millisecond) { if (_updates.Count == 0) return; foreach (var uiview in _updates) { uiview.LateUpdate(millisecond); } _updates.Clear(); } void IDisposable.Dispose() { _updates.Clear(); foreach (var async in _loadingMap.Values) { async.RemoveAll(); } _loadingMap.Clear(); foreach (var uiview in _closedMap.Values) { DestroyUIView(uiview); } _closedMap.Clear(); foreach (var uiview in _openedMap.Values) { DestroyUIView(uiview); } _openedMap.Clear(); (_uitree as IDisposable)?.Dispose(); (_assetModule as IDisposable)?.Dispose(); _assetModule = null; _context = null; } IUIAssetModule IUIAssetModuleCreator.Create(UIContext context) { return new UIAssetModule(context); } #endregion #region 内部函数 private void DestroyUIView(IUIView view) { var uiPanel = view.Panel as UIPanel; (view as IDisposable).Dispose(); _assetModule.Recycle(uiPanel.gameObject, true); } #endregion } }