167 lines
4.3 KiB
Markdown
167 lines
4.3 KiB
Markdown
# P0-8: UIManager 需求详细文档
|
||
|
||
## 对齐说明
|
||
|
||
本文档以 `docs/requirements/p0-requirements-set.md` 为准。P0 UIManager 支持可配置层级和层内 LIFO 栈,但不做完整导航路由系统。`UIPanelAttribute` 明确包含 `path` 参数。
|
||
|
||
## 目标
|
||
|
||
提供 MVVM Panel 生命周期管理、运行时层级注册、层内栈式打开关闭、手写 Bind/Unbind 和基础缓存/销毁策略。
|
||
|
||
## 层级注册
|
||
|
||
```csharp
|
||
public sealed class UIManager
|
||
{
|
||
public void RegisterLayer(
|
||
string name,
|
||
Canvas canvas,
|
||
int sortOrder,
|
||
PanelStrategy strategy = PanelStrategy.Destroy);
|
||
}
|
||
|
||
public enum PanelStrategy
|
||
{
|
||
Destroy,
|
||
Cache
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- P0 不强制固定 `Bottom/Middle/Top`。
|
||
- 推荐默认层级为 `background / hud / popup / dialog / system`。
|
||
- 项目可只注册部分层级。
|
||
- 未注册层级打开 Panel 时抛异常。
|
||
|
||
## Panel Attribute
|
||
|
||
```csharp
|
||
[AttributeUsage(AttributeTargets.Class)]
|
||
public sealed class UIPanelAttribute : Attribute
|
||
{
|
||
public string Layer { get; }
|
||
public string Path { get; }
|
||
public PanelStrategy? OverrideStrategy { get; }
|
||
|
||
public UIPanelAttribute(string layer);
|
||
public UIPanelAttribute(string layer, string path);
|
||
public UIPanelAttribute(string layer, PanelStrategy overrideStrategy);
|
||
public UIPanelAttribute(string layer, string path, PanelStrategy overrideStrategy);
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- `Layer` 必填。
|
||
- `Path` 可选;未填时按命名约定推导。
|
||
- `OverrideStrategy` 可选,优先于层级默认策略。
|
||
- 说明:C# Attribute 构造参数不支持 `Nullable<T>`,因此 `OverrideStrategy` 属性保持 nullable,但通过重载表达“未指定”和“指定覆盖策略”。
|
||
|
||
## Panel 基类
|
||
|
||
```csharp
|
||
public abstract class UIPanelBase<TViewModel> : MonoBehaviour
|
||
{
|
||
protected TViewModel ViewModel { get; private set; }
|
||
protected CompositeDisposable Disposables { get; } = new();
|
||
|
||
public void Bind(TViewModel viewModel)
|
||
{
|
||
ViewModel = viewModel;
|
||
OnBind(viewModel);
|
||
}
|
||
|
||
public virtual void Unbind()
|
||
{
|
||
Disposables.Clear();
|
||
}
|
||
|
||
protected abstract void OnBind(TViewModel viewModel);
|
||
}
|
||
```
|
||
|
||
## 打开与关闭接口
|
||
|
||
```csharp
|
||
public sealed class UIManager
|
||
{
|
||
public Task<TPanel> OpenAsync<TPanel, TViewModel>(
|
||
TViewModel viewModel,
|
||
CancellationToken cancellationToken)
|
||
where TPanel : UIPanelBase<TViewModel>;
|
||
|
||
public void Close<TPanel>();
|
||
public void CloseLayer(string layerName);
|
||
public void CloseAll();
|
||
public bool IsOpen<TPanel>();
|
||
}
|
||
```
|
||
|
||
## 生命周期
|
||
|
||
```text
|
||
OpenAsync:
|
||
1. 读取 UIPanelAttribute
|
||
2. 校验层级已注册
|
||
3. 解析资源路径
|
||
4. IResourceService.LoadAsync<GameObject>
|
||
5. Instantiate 到目标 Canvas
|
||
6. Bind(viewModel)
|
||
7. SetActive(true)
|
||
8. 压入层内栈
|
||
|
||
Close:
|
||
1. 校验目标 Panel 是所在层级栈顶
|
||
2. 从栈弹出
|
||
3. Unbind()
|
||
4. Destroy 策略:Destroy GameObject 并释放资源 handle
|
||
5. Cache 策略:SetActive(false),保留实例和资源 handle
|
||
```
|
||
|
||
路径约定:
|
||
|
||
```text
|
||
ShopPanel -> UI/Shop/Prefab
|
||
ConfirmPanel -> UI/Confirm/Prefab
|
||
MainHudPanel -> UI/MainHud/Prefab
|
||
```
|
||
|
||
## 暂不做
|
||
|
||
- 自动 UI 绑定。
|
||
- 导航路由系统。
|
||
- 跨 Feature 页面恢复。
|
||
- Panel 预加载。
|
||
- SafeArea。
|
||
- 多语言 UI 切换。
|
||
- 红点/通知系统。
|
||
- 复杂转场动画。
|
||
|
||
## 验收标准
|
||
|
||
| # | 标准 | 通过条件 |
|
||
|---|------|---------|
|
||
| 1 | 注册层级 | RegisterLayer 后 Panel 可挂载到对应 Canvas |
|
||
| 2 | Attribute 层级 | Panel 通过 UIPanelAttribute 找到层级 |
|
||
| 3 | path 参数 | Attribute 指定 path 时按指定路径加载 |
|
||
| 4 | 路径约定 | 未指定 path 时按命名约定加载 |
|
||
| 5 | Open | 异步加载 Prefab、实例化、Bind、入栈 |
|
||
| 6 | Close | 栈顶 Panel Unbind 并按策略关闭 |
|
||
| 7 | LIFO | 关闭非栈顶 Panel 抛异常 |
|
||
| 8 | Cache | Cache Panel 再次打开时复用并重新 Bind |
|
||
| 9 | Destroy | Destroy Panel 关闭后释放资源 handle |
|
||
| 10 | CloseLayer | 只关闭指定层级 |
|
||
| 11 | CloseAll | 关闭所有层级 |
|
||
| 12 | Bind 失败 | 清理已创建对象和资源 handle 后抛异常 |
|
||
|
||
## 依赖关系
|
||
|
||
```text
|
||
UIManager
|
||
├── IResourceService
|
||
├── R3
|
||
├── Unity Canvas / GameObject / MonoBehaviour
|
||
└── CancellationToken
|
||
```
|