Files
FlowScope/docs/requirements/p0-uimanager.md
2026-05-18 12:11:50 +08:00

167 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```