继续重构调整(UI)

- 引入 UniTask 和异步版本的 UIModule
- 调整 Runtime/UIBase 和 Presentation 下的脚本命名空间到 SepCore.UI
- 将原来的 5 层 UI 迁移到异步实现
- 规范各层的 UI 脚本命名
This commit is contained in:
SepComet
2026-06-03 09:58:37 +08:00
parent 6b8a6a8789
commit 7bba8bbb80
552 changed files with 83648 additions and 2726 deletions
@@ -1,31 +1,91 @@
using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using SepCore.Definition;
using SepCore.UI;
using UnityEngine;
using UnityGameFramework.Runtime;
using UI;
namespace CustomComponent
namespace SepCore.CustomComponent
{
public class UIRouterComponent : GameFrameworkComponent
{
[Serializable]
public class ControllerBinding
{
[SerializeField] private UIFormType _uiFormType = UIFormType.Undefined;
[SerializeField] private string _controllerTypeName;
public UIFormType UIFormType => _uiFormType;
public string ControllerTypeName => _controllerTypeName;
}
[SerializeField] private List<ControllerBinding> _controllerBindings = new();
private readonly Dictionary<UIFormType, IUIFormController> _routeControllers = new();
private readonly Dictionary<UIFormType, Func<IUIFormController>> _controllerFactories = new();
protected override void Awake()
{
base.Awake();
RegisterSerializedBindings();
}
public void RegisterController(UIFormType uiFormType, Func<IUIFormController> controllerFactory)
{
if (controllerFactory == null)
{
Log.Error("UIRouterComponent.RegisterController() controllerFactory is invalid.");
return;
}
if (_routeControllers.TryGetValue(uiFormType, out IUIFormController controller))
{
controller.CloseUIAsync().Forget();
_routeControllers.Remove(uiFormType);
}
_controllerFactories[uiFormType] = controllerFactory;
}
public void RegisterController<TController>(UIFormType uiFormType)
where TController : IUIFormController, new()
{
RegisterController(uiFormType, () => new TController());
}
public void BindUIUseCase(UIFormType uiFormType, IUIUseCase useCase)
{
IUIFormController controller = GetOrCreateController(uiFormType);
if (controller == null)
{
return;
}
controller.BindUseCase(useCase);
}
public int? OpenUI(UIFormType uiFormType, object userData = null)
public UniTask<int?> OpenUIAsync(UIFormType uiFormType, object userData = null, float timeout = 30f)
{
IUIFormController controller = GetOrCreateController(uiFormType);
return controller.OpenUI(userData);
if (controller == null)
{
return UniTask.FromResult<int?>(null);
}
return controller.OpenUIAsync(userData, timeout);
}
public void CloseUI(UIFormType uiFormType)
public UniTask CloseUIAsync(UIFormType uiFormType, object userData = null, float timeout = 30f)
{
IUIFormController controller = GetOrCreateController(uiFormType);
controller.CloseUI();
if (controller == null)
{
return UniTask.CompletedTask;
}
return controller.CloseUIAsync(userData, timeout);
}
private IUIFormController GetOrCreateController(UIFormType uiFormType)
@@ -35,67 +95,82 @@ namespace CustomComponent
return controller;
}
string typename = $"UI.{uiFormType}Controller";
Type controllerType = Type.GetType(typename);
if (controllerType == null)
if (!_controllerFactories.TryGetValue(uiFormType, out Func<IUIFormController> controllerFactory))
{
controller = new DefaultUIFormController(uiFormType);
Log.Error("UIRouterComponent requires a controller binding for '{0}'.", uiFormType.ToString());
return null;
}
else
controller = controllerFactory();
if (controller == null)
{
controller = (IUIFormController)Activator.CreateInstance(controllerType);
Log.Error("UIRouterComponent controller factory for '{0}' returned null.", uiFormType.ToString());
return null;
}
_routeControllers.Add(uiFormType, controller);
return controller;
}
private void RegisterSerializedBindings()
{
if (_controllerBindings == null || _controllerBindings.Count == 0)
{
return;
}
HashSet<UIFormType> seen = new();
foreach (ControllerBinding binding in _controllerBindings)
{
if (binding == null || binding.UIFormType == UIFormType.Undefined ||
string.IsNullOrWhiteSpace(binding.ControllerTypeName))
{
continue;
}
if (!seen.Add(binding.UIFormType))
{
Log.Warning("UIRouter duplicate binding for '{0}', later one overrides earlier one.",
binding.UIFormType.ToString());
}
Type controllerType = Type.GetType(binding.ControllerTypeName);
if (controllerType == null)
{
Log.Warning("UIRouter binding type not found: {0}", binding.ControllerTypeName);
continue;
}
if (!typeof(IUIFormController).IsAssignableFrom(controllerType))
{
Log.Warning("UIRouter binding type '{0}' does not implement IUIFormController.",
binding.ControllerTypeName);
continue;
}
RegisterController(binding.UIFormType, () => CreateController(controllerType));
}
}
private static IUIFormController CreateController(Type controllerType)
{
object instance = Activator.CreateInstance(controllerType);
if (instance is IUIFormController controller)
{
return controller;
}
return null;
}
private void OnDestroy()
{
foreach (KeyValuePair<UIFormType, IUIFormController> pair in _routeControllers)
{
pair.Value.CloseUI();
pair.Value.CloseUIAsync().Forget();
}
_routeControllers.Clear();
}
private class DefaultUIFormController : IUIFormController
{
private readonly UIFormType _uiFormType;
private int? _lastSerialId;
public DefaultUIFormController(UIFormType uiFormType)
{
_uiFormType = uiFormType;
}
public int? OpenUI(object userData = null)
{
_lastSerialId = GameEntry.UI.OpenUIForm(_uiFormType, userData);
return _lastSerialId;
}
public void CloseUI()
{
if (_lastSerialId.HasValue)
{
GameEntry.UI.CloseUIForm(_lastSerialId.Value);
_lastSerialId = null;
return;
}
UGuiForm uiForm = GameEntry.UI.GetUIForm(_uiFormType);
if (uiForm != null)
{
GameEntry.UI.CloseUIForm(uiForm);
}
}
public void BindUseCase(IUIUseCase useCase)
{
}
}
}
}