From ab4fbfa628bd17b1e6142d9591217fcd8869d4e2 Mon Sep 17 00:00:00 2001 From: changqian <17865945142@163.com> Date: Tue, 20 Oct 2026 10:15:09 +0800 Subject: [PATCH] =?UTF-8?q?UnityAI=E6=96=B0=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/frameworks/UI窗口系统/README.md | 4 +- modules/frameworks/UI窗口系统/开发指南.md | 29 ++++- modules/frameworks/UI窗口系统/界面拼接.md | 109 +++++++++++++++--- .../MCP工具/Codex_Unity_MCP使用规则.md | 18 ++- modules/frameworks/编辑器工具/UI拼接工具.md | 2 + rules/20-开发规则.md | 6 +- rules/40-工作流清单.md | 2 +- 7 files changed, 137 insertions(+), 33 deletions(-) diff --git a/modules/frameworks/UI窗口系统/README.md b/modules/frameworks/UI窗口系统/README.md index 4377c5e..2b5aff0 100644 --- a/modules/frameworks/UI窗口系统/README.md +++ b/modules/frameworks/UI窗口系统/README.md @@ -47,14 +47,14 @@ HFFunCatalogue.UIManager.OpenWindow() - 打开和关闭统一通过 `HFFunCatalogue.UIManager`。 - `OnOpen` 与 `OnClose` 中的事件注册和释放保持对称。 - 引用绑定优先使用项目 UIMono/SFUI 流程,不堆叠 `transform.Find`。 -- 单列虚拟列表使用 LoopListView2 包装接口,多列布局使用 LoopGridView 包装接口。 +- 动态列表优先使用项目的 `SFUI_ScrollRect`;按当前实现选择 `BindEvent` 或已接入的 LoopListView2 / LoopGridView 包装,见 [UI 开发指南](开发指南.md)。 - 模板节点在 Prefab 中保持禁用,由虚拟列表创建实例。 - UI 修改必须验证脚本、Prefab 层级、RectTransform、组件状态和运行时效果。 ## 子文档 - [UI 开发指南](开发指南.md) -- [界面拼接](界面拼接.md) +- [界面拼接](界面拼接.md):根据示意图制作 UI 的完整规则,涵盖分辨率确认、切图尺寸与效率、三宫格/九宫格、SFUI、共享页签和视觉验收。 - [UI 拼接工具](../编辑器工具/UI拼接工具.md) ## 文档关联 diff --git a/modules/frameworks/UI窗口系统/开发指南.md b/modules/frameworks/UI窗口系统/开发指南.md index c6a05ed..455ae88 100644 --- a/modules/frameworks/UI窗口系统/开发指南.md +++ b/modules/frameworks/UI窗口系统/开发指南.md @@ -49,7 +49,26 @@ HFFunCatalogue.UIManager.OpenWindow(); ## 三、单列虚拟列表 -单列或单行滚动使用 LoopListView2 包装接口: +### 选择当前项目支持的接口 + +动态列表优先通过项目的 `SFUI_ScrollRect` 使用。先检查当前源码、Prefab 和相似窗口,确认使用 `BindEvent` 还是 SuperScrollView 包装;两套入口不要混用,也不要仅因本文示例而迁移已有列表。视觉、共享页签和 Item 复用规则见 [界面拼接](界面拼接.md)。 + +### BindEvent 接口 + +支持该接口的项目,通过以下四个回调绑定列表;名称与类型以目标项目实际签名为准: + +| 参数 | 职责 | +|---|---| +| `Func _getItemCount` | 返回当前数据数量,数据未就绪时返回 `0` | +| `Func _getItemTemplete` | 按数据索引返回模板 GameObject;相同结构返回同一模板 | +| `Action _updateItem` | 依据当前 Item 的数据索引完整刷新显示 | +| `Func _funcBindSimulateBehaviour` | 为 Item 绑定项目模拟行为脚本,避免重复绑定 | + +模板选择回调返回的是模板对象,不是 LoopListView2 的模板索引。绑定后按当前实现的刷新入口更新列表;不要照搬另一套包装的 `RefreshDataTotalCount`。同时检查空列表、尺寸变化、布局缓存与初始化要求。模板组件遵循项目序列化方式,不预先重复挂载列表动态添加的组件。 + +### LoopListView2 包装接口 + +已接入该包装的项目,单列或单行滚动使用以下接口: ```csharp m_List.SetLoopListViewItemPrefabs( @@ -83,7 +102,7 @@ m_List.RefreshDataTotalCount(m_DataList == null ? 0 : m_DataList.Count); ## 四、多列虚拟列表 -存在固定列数、`GridLayoutGroup` 语义或二维排布时使用 LoopGridView: +已接入 SuperScrollView 包装的项目,存在固定列数、`GridLayoutGroup` 语义或二维排布时使用 LoopGridView: ```csharp m_Grid.SetLoopGridViewItemPrefabs( @@ -114,9 +133,9 @@ m_Grid.RefreshGridDataTotalCount(m_DataList == null ? 0 : m_DataList.Count); - 模板节点保持 `SetActive(false)`,但必须位于窗口层级中以便引用收集。 - `SFUI_ScrollRect`、viewport、content 和模板引用必须完整。 -- 虚拟列表初始化会关闭旧 `LayoutGroup` 和 `ContentSizeFitter`,运行时布局由 SuperScrollView 管理。 -- 不要因为这些旧组件在运行时被关闭就重新勾选或依赖它们计算虚拟列表尺寸。 -- 检查模板上的 `LoopListViewItem2` 或 `LoopGridViewItem`;包装层会补组件,但 Prefab 结构仍需正确。 +- SuperScrollView 包装初始化会关闭旧 `LayoutGroup` 和 `ContentSizeFitter`,运行时布局由该包装管理;不要重新勾选或依赖旧组件计算尺寸。 +- 使用 `BindEvent` 时检查其实际布局与初始化机制,不套用 SuperScrollView 的组件关闭规则。 +- 使用 SuperScrollView 包装时检查模板上的 `LoopListViewItem2` 或 `LoopGridViewItem`;包装层会补组件,但 Prefab 结构仍需正确。 - UIMono 收集需要包含 inactive 子节点,不能只扫描激活节点。 ## 六、验证清单 diff --git a/modules/frameworks/UI窗口系统/界面拼接.md b/modules/frameworks/UI窗口系统/界面拼接.md index bd23e7d..f33d720 100644 --- a/modules/frameworks/UI窗口系统/界面拼接.md +++ b/modules/frameworks/UI窗口系统/界面拼接.md @@ -1,13 +1,19 @@ # UI 界面拼接 +本文是根据示意图制作 UI 窗口的完整规则来源。生命周期和列表 API 见 [UI 开发指南](开发指南.md),通用执行与授权流程见 [工作流清单](../../../rules/40-工作流清单.md)。其他入口只引用本文,不重复维护整套规则。 + ## 一、输入与目标 -开始拼接前同时确认: +开始拼接前,先向开发者确认目标分辨率、横竖屏、SafeArea 与屏幕适配要求,以及窗口是全屏、弹窗还是局部面板。已经明确提供的信息不重复询问;项目现有配置可作为确认依据,但不得直接套用某个项目的分辨率。 + +同时检查: - 设计原图、标注图或 PSD 中的尺寸、间距和层级。 - 项目现有 Sprite、SpriteAtlas、字体、材质和可复用 Prefab。 - 目标窗口名、Prefab 路径、Canvas 层级和脚本绑定方式。 -- 目标分辨率、SafeArea、横竖屏和滚动区域。 +- 示意图对应的状态、滚动区域和本次需要实现的交互范围。 + +先理解当前项目的窗口基类、Item 基类、SFUI/UIMono、资源加载、节点绑定与事件规范,优先复用相似窗口。给出简短的节点、切图、复用和验证方案;已明确授权的方案直接实施。不为拼界面另建框架或修改无关业务、第三方库。 不能只凭截图选择近似资源。设计图中的可检查对象必须使用语义正确的现有资源;缺失资源应明确记录,不能用无关图片顶替。 @@ -31,45 +37,116 @@ WindowName - 节点命名应能对应脚本字段和功能,例如 `Btn_Close`、`Txt_Title`、`Img_Icon`。 - 复用 Item 或子面板时保持独立根节点,便于 UIMono 绑定和对象复用。 - 全屏背景使用稳定锚点;局部模块使用明确尺寸,避免依赖编辑器当前分辨率。 +- 背景主要承载底板和固定装饰;关闭按钮、页签、操作按钮及其状态独立实现,不烘焙在背景中。 +- 动态名称、进度、数量和提示使用文字组件;固定装饰性标题可以使用图片,但不能妨碍交互、适配及明确要求的本地化。 +- 不用整张效果图替代可交互窗口;按示意图核对整体轮廓、比例、间距、层级和遮挡关系。 -## 三、列表选择 +## 三、画布与图片尺寸 -- 单列或单行滚动:LoopListView2。 -- 固定多列或网格:LoopGridView。 -- 模板节点保持禁用,尺寸、pivot 和滚动方向必须匹配。 -- 虚拟列表不依赖旧 LayoutGroup/ContentSizeFitter 运行时排版。 -- 具体初始化接口见 [UI 开发指南](开发指南.md)。 +- 以开发者确认的分辨率建立基准画布,按适配要求统一 CanvasScaler、Sprite PPU 与项目约定。 +- RectTransform 缩放默认保持 `1`,主要通过尺寸、锚点和布局控制显示,不靠缩小 Transform 匹配超大源图。 +- **普通、不可拉伸的图片,执行 `SetNativeSize()` 后应达到目标画布中的预期尺寸。** 检查导入后的 Sprite 尺寸及 PPU 与 Canvas 的关系,不能只检查源 PNG。 +- 三宫格、九宫格图片使用紧凑源图,通过 RectTransform 设置最终显示尺寸。 -## 四、拼接流程 +## 四、切图与资源效率 -1. 读取 [UnityAI README](../../../README.md) 中的 UI 入口和相关指南。 +- 每个独立 UI 元素默认使用单张图片,**Sprite Mode 默认 Single**。开发者有单独要求时,允许 Multiple 或其他组织方式,不作绝对禁止。 +- Sprite Mode 与图集打包分别处理;Single 图片仍可按项目规范进入 SpriteAtlas。名称应表达用途和状态。 +- **普通图片在保证 `SetNativeSize()` 尺寸正确、最终显示不模糊的前提下,以尽量少占内存、尽量快加载为原则。** 避免超过实际需求的像素尺寸,不用过度降采样或压缩牺牲清晰度。 +- 去除无用透明留白,保留必要的阴影、描边、柔边和装饰;裁剪后同步调整定位,保持视觉位置一致。 +- 清除毛刺、杂点、残留底色、白边和黑边,在浅色、深色背景下检查透明边缘。缩小后重新检查,不能只验收原始大图。 +- 按目标平台、透明通道和图片内容选择纹理格式与压缩;Mipmap、Read/Write、过滤和图集设置按用途配置,不盲目沿用默认值。 +- 不单凭磁盘文件大小判断运行时内存与加载效率;需要比较方案时,以导入信息及目标平台测量为依据。 +- 缩放、压缩或打图集后检查最终导入和渲染结果。 + +## 五、三宫格与九宫格 + +- 仅纵向伸缩的图片优先纵向三宫格,仅横向伸缩的图片优先横向三宫格。 +- 同时改变宽高的规则面板、卡片和按钮优先九宫格。 +- Border 必须保护圆角、描边、阴影和固定装饰;拉伸区域选择适合伸展的纯色、渐变或规则区域。 +- 可以缩减源图中可拉伸区域的像素尺寸,保留固定边缘;检查最终尺寸下的接缝、渐变和装饰是否自然。 +- 复杂插画、不规则图标或无法合理分离拉伸区域的图片,不强行切片。 +- 修改源图尺寸后重新检查 Border,并配置对应 Image 的切片显示方式,不能只写 Border 而仍按普通图片整体拉伸。 + +## 六、组件、布局与交互 + +- 使用项目对应的 SFUI 图片、文字、按钮、Toggle、ScrollRect 等组件,以及既有节点行为和绑定流程。 +- 组件接口、序列化与初始化以当前项目源码为准,不凭名称或原生 UGUI 经验推断。 +- 按适配要求配置锚点、pivot、布局约束与遮罩;避免布局组件互相冲突或依赖偶然执行顺序。 +- 纯装饰图片与文字关闭不必要的射线检测,避免遮挡按钮、页签和滚动操作。 +- 点击区域与视觉表达一致,必要时按项目约定扩大;检查长文本、数量位数及动态内容变化。 + +## 七、页签与共享内容 + +- 互斥页签使用 **Toggle + ToggleGroup**;SFUI 项目使用对应的 SFUI Toggle。 +- 普通态与选中态由 Toggle 状态驱动;监听变化时仅在选中状态执行切页,正确设置默认选中项并避免初始化重复刷新。 +- 除非开发者或项目另有要求,不用普通按钮和独立布尔变量重复实现页签状态。 +- 展示结构一致的页签共用一个内容面板、列表和 Item 模板,切页更新数据与必要状态,不复制两套完整界面。 +- 文字、图标、奖励或进度不同不是新增模板的理由;只有结构确实不同时才增加模板。 +- 明确切页是否回到顶部、同页更新是否保持滚动位置。 + +## 八、列表选择与复用 + +- 动态列表优先使用项目的 **SFUI_ScrollRect**。先读取当前实现和使用示例,再选择 `BindEvent` 或项目已接入的 LoopListView2 / LoopGridView 包装,不能混用或因拼 UI 强行迁移。 +- `BindEvent` 按数据索引动态选择模板;参数职责、刷新入口和其他包装示例统一见 [UI 开发指南](开发指南.md)。 +- 使用列表已有的创建与复用机制,不额外手动批量生成节点。 +- Item 每次刷新完整更新文字、图标、进度、按钮状态、可选节点与高度,避免旧状态残留及回调持有过期数据。 +- 模板保持禁用,尺寸、pivot 和滚动方向匹配;组件遵循当前框架要求,不重复序列化由列表运行时添加的组件。 +- LayoutGroup/ContentSizeFitter 是否保留或关闭取决于当前列表实现;不要混用不同包装的布局机制。 + +## 九、数据与生命周期边界 + +- 仅拼 UI 时,不擅自扩展协议、数据模型和业务逻辑。 +- 接入业务时由管理器持有和更新业务数据,通过项目事件机制通知界面;采用 CTC 的项目使用 CTC 刷新。 +- 界面负责展示与转交操作,不自行维护另一份权威业务状态。 +- 订阅和解除成对,重复开关、启用窗口及 Item 复用不能叠加监听;生命周期具体约定见 [UI 开发指南](开发指南.md)。 +- 预览数据与正式运行数据分离,不能覆盖服务器状态。 + +## 十、拼接流程 + +1. 按 [AI 接入入口](../../../ai/AI接入入口.md) 读取规则和 UI 指南,完成本文的需求确认。 2. 检查目标 Prefab 是否已存在,导出或读取当前层级,避免覆盖有效结构。 3. 枚举目标资源目录和图集,建立设计元素到实际资源的对应关系。 4. 确定窗口根尺寸、锚点、主要功能区和列表类型。 5. 使用 Unity Editor 手工拼接,或通过 MCP 的 JSON 生成工具创建基础结构。 -6. 绑定 SFUI/UIMono 组件与业务脚本,补齐交互、列表和动态数据。 +6. 绑定 SFUI/UIMono 组件与脚本,按已授权范围补齐交互、列表和数据。 7. 刷新资源并检查 Console、Prefab 序列化结构和运行时显示。 -8. 对照原图检查尺寸、层级、颜色、字体、九宫格和点击区域。 +8. 按本文验收清单对照原图检查实际画面和交互。 JSON 生成适合批量创建稳定层级和组件,不代替视觉校对、业务绑定和运行时验证。 -## 五、修改已有 Prefab +## 十一、修改已有 Prefab 与资源维护 - 先读取现有 Prefab 和脚本引用,再调整层级或组件。 - 移动、重命名节点前搜索 `FindUICtrlByName`、序列化字段和生成绑定代码。 - 只修改目标节点,避免让 Unity 重序列化无关 Prefab。 - 组件勾选状态属于 Prefab 行为的一部分;修复显示问题时同时检查 `enabled` 与 GameObject active。 -- 列表迁移后,旧布局组件可保留序列化参数作为参考,但运行时由新列表包装关闭。 +- 若已授权迁移到会关闭旧布局的列表包装,可保留旧组件序列化参数作为参考,运行时由新包装管理布局;不将该行为套用到所有列表实现。 +- 原始示意图、源图和中间素材保存在约定的美术或策划归档目录,运行时目录只保留实际需要的资源。 +- 删除资源前检查 Prefab、场景、代码、配置、图集和生成工具引用,并遵守开发者授权范围。 +- 有生成工具时同步修改生成源,避免重新生成旧布局或无用资源;不能只手工修补生成结果。 +- 替换已有资源时尽量保留 GUID,避免引用断裂;保留用户已有的无关修改。 -## 六、验收 +## 十二、验收与交付 + +在开发者确认的目标分辨率及必要的适配尺寸下实际渲染,保存可复核的对照画面并检查: - Prefab 路径和窗口 attribute 一致。 - Sprite、字体、材质和图集引用有效。 - 锚点、pivot、sizeDelta 和层级与设计目标一致。 - 按钮、文本、列表、进度和弹窗交互正确。 -- 空数据、极长文本、不同分辨率和重复打开不破版。 +- 背景、装饰、整体比例、间距、颜色和字体符合示意图,普通图片 SetNativeSize 尺寸正确且清晰。 +- 三宫格、九宫格的边角、接缝、渐变和拉伸效果自然;压缩、打图集后的透明边缘和清晰度符合要求。 +- 页签普通态、选中态、内容切换正确,同结构页签共享列表和模板。 +- 空列表、短列表、长列表、滚动到底部、内容高度变化及 Item 复用正常。 +- 极长文本、不同分辨率和重复打开不破版,业务涉及的未完成、可操作、已完成、禁用等状态正确。 +- 重复切页、开关及启用窗口无重复回调、状态残留或缺失引用。 - Unity Console 无本次新增 Error,运行时实际显示通过确认。 +编译通过、Prefab 保存成功或 JSON 生成成功不能代替视觉和交互验收。无法完成的检查明确说明,不能宣称已验证。 + +交付时说明修改的窗口、脚本和资源,确认的基准分辨率与适配方式,主要图片尺寸及三宫格/九宫格设置,已完成的编译、视觉和交互验证,以及未验证内容、已知限制和必要后续操作。 + ## 文档关联 | 文档 | 关联原因 | diff --git a/modules/frameworks/编辑器工具/MCP工具/Codex_Unity_MCP使用规则.md b/modules/frameworks/编辑器工具/MCP工具/Codex_Unity_MCP使用规则.md index 09e2ff2..5521101 100644 --- a/modules/frameworks/编辑器工具/MCP工具/Codex_Unity_MCP使用规则.md +++ b/modules/frameworks/编辑器工具/MCP工具/Codex_Unity_MCP使用规则.md @@ -2,7 +2,7 @@ ## 一、定位 -Codex 通过本地 stdio MCP Server 调用 Unity Editor 内的 HTTP Bridge。Bridge 只监听 `127.0.0.1:17777`,并把 Unity API 工作排队到 Editor 主线程执行。 +Codex 通过本地 stdio MCP Server 调用 Unity Editor 内的 HTTP Bridge。Bridge 监听 `127.0.0.1` 上的可配置端口(默认 17777,按项目隔离),并把 Unity API 工作排队到 Editor 主线程执行。 当前能力只面向 Unity Editor 自动化,不覆盖 Play Mode、真机运行时调试或远程网络访问。 @@ -11,7 +11,7 @@ Codex 通过本地 stdio MCP Server 调用 Unity Editor 内的 HTTP Bridge。Bri ```text MCP Server: UnityAI/Tools/CodexUnityMcp/ Codex config: .codex/config.toml -Unity Bridge: http://127.0.0.1:17777 +Unity Bridge: http://127.0.0.1:<可配置端口> (默认 17777,详见第七节) ``` 本文档不维护 Unity Bridge 的打开方式或 Unity Editor 内部目录结构。 @@ -152,9 +152,17 @@ UI 任务必须先从 [UnityAI README](../../../../README.md) 进入 UI 文档 ### 端口占用 -- Bridge 如果发现同端口已经存在有效服务,应连接到现有监听状态而不是重复启动。 -- 不能通过同时启动多个监听器解决端口冲突。 -- 状态仍不一致时记录端口、进程和 Bridge 状态,再处理占用来源。 +端口按以下优先级解析,冲突自动顺延,必要时手动固定: + +1. 环境变量 `UNITY_MCP_PORT`(最高优先,手动指定绝对端口)。 +2. 项目根目录 `UnityMcpPort.txt`(一行数字,可随项目入 Git,便于固定端口)。 +3. 项目路径 FNV-1a 哈希派生(同一项目在任意机器得到同一端口,便于写死配置)。 +4. 默认端口 17777。 + +- 多个 Unity 项目**各自独立监听不同端口**(按项目隔离),允许同时运行多个监听器,互不干扰。 +- 绑定首选端口失败时,Bridge 向后递增重试(最多 20 个端口),不再静默“连接到现有监听”,避免请求串到别的项目。 +- 实际端口与首选端口不一致时,Unity Console 输出 Warning,并提示把 `UNITY_MCP_PORT` 或 `UnityMcpPort.txt` 设为实际端口(或释放首选端口)以保持 MCP 路由稳定。 +- 连接恢复前不执行其他 Unity 工具;状态仍不一致时记录端口、进程和 Bridge 状态,再处理占用来源。 ### 刷新后连接失败 diff --git a/modules/frameworks/编辑器工具/UI拼接工具.md b/modules/frameworks/编辑器工具/UI拼接工具.md index ca71dd7..b8e02cb 100644 --- a/modules/frameworks/编辑器工具/UI拼接工具.md +++ b/modules/frameworks/编辑器工具/UI拼接工具.md @@ -19,6 +19,8 @@ UI 拼接工具通过 JSON 与 Unity Prefab 双向转换,帮助 Codex 和开 根节点使用 `UILayoutData`: +以下尺寸仅演示 JSON 字段,不是默认制作分辨率。实际尺寸须按 [界面拼接](../UI窗口系统/界面拼接.md) 向开发者确认后填写。 + ```json { "name": "ExampleWindow", diff --git a/rules/20-开发规则.md b/rules/20-开发规则.md index a9ec6a6..9fdb163 100644 --- a/rules/20-开发规则.md +++ b/rules/20-开发规则.md @@ -51,13 +51,11 @@ ## UI 与 Prefab - 修改前同时读取窗口脚本、UIMono、Prefab 层级和相关资源。 -- 单列虚拟列表使用 `SetLoopListViewItemPrefabs`、`InitListView`、`RefreshDataTotalCount`。 -- 多列虚拟列表使用 `SetLoopGridViewItemPrefabs`、`InitGridView`、`RefreshGridDataTotalCount`。 -- 模板节点保持禁用,由列表运行时创建实例;不要依赖旧 LayoutGroup 或 ContentSizeFitter 驱动虚拟列表。 +- 动态列表使用项目的 SFUI_ScrollRect,接口选择、模板和布局约束统一见 [UI 开发指南](../modules/frameworks/UI窗口系统/开发指南.md),不把某种包装的 API 套用到其他实现。 - Prefab 修改检查锚点、pivot、sizeDelta、组件启用状态、序列化引用和实际显示。 - 避免文本方式大范围重写 Prefab;优先使用 Unity Editor、MCP 或结构化序列化工具。 -详细规则见 [UI 窗口系统](../modules/frameworks/UI窗口系统/README.md)。 +窗口框架见 [UI 窗口系统](../modules/frameworks/UI窗口系统/README.md);根据示意图拼 UI 的分辨率确认、切图、资源效率与验收规则统一见 [界面拼接](../modules/frameworks/UI窗口系统/界面拼接.md)。 ## 资源与生成规则 diff --git a/rules/40-工作流清单.md b/rules/40-工作流清单.md index fa59228..d1c637e 100644 --- a/rules/40-工作流清单.md +++ b/rules/40-工作流清单.md @@ -100,7 +100,7 @@ dotnet build GameHF.csproj --no-restore -v:minimal 1. 先读 [UI 开发指南](../modules/frameworks/UI窗口系统/开发指南.md) 和 [界面拼接](../modules/frameworks/UI窗口系统/界面拼接.md)。 2. 同时检查 Prefab 层级、脚本绑定、模板节点、布局组件和数据刷新时机。 -3. 单列列表使用 LoopListView2 接口,多列布局使用 LoopGridView 接口。 +3. 按 [界面拼接](../modules/frameworks/UI窗口系统/界面拼接.md) 向开发者确认目标分辨率与适配要求;列表接口按当前项目实现选择,不强制套用 LoopListView2 / LoopGridView。 4. 列表初始化放在一次性生命周期,数据数量刷新放在窗口打开或数据变化时。 5. 完成后验证空数据、少量数据、超出视口、重复打开和回收重用。