sdk(ui): W_LISTVIEW 虚拟化层 — 固定 item 池 + 多行富 item + 完全自绘 (§5.5)

在既有 W_LISTVIEW (src2 每帧取行) 之上叠加虚拟化层 (API 追加式, 旧 API 一字不改):
- 数据源 count_fn + bind_fn (index, meow_lv_item*, ctx); count 每帧实时查 (任意长度≥65535,
  不常驻 item 对象); bind 仅在行进入视口时被调一次
- 固定 item 池: 视口行数+2 静态槽 (有界 ≤96), 回滚不重绑 (同 index 命中同槽); 整表扫过后
  wrap 回收合法但每次 draw 有界 (≤视口窗口)
- 多行富 item: 主标题/副标题/左图标·缩略图/右尾件; 行高 set_item_h(px) 或 set_item_tier(1→48/2→56);
  默认 renderer 主题语义色绘制; set_item_draw 完全自绘; section 段头占位行(非粘性); 空态占位
- 集成: tap_at→meow_ui_focus_acquire (§6.4); meow_scroll_wrap(lv,1) track+fling+snap(行边界);
  选中/按压态走主题; enabled=0 变淡不响应
- 兼容: src2==NULL 走既有路径; W_LIST/W_LISTVIEW 单行用法零改动

验证(宿主): 新测试 test_meow_ui_listvirt T1-T5 全 44 PASS (10000 项滚动窗口内容正确/hit 映射/
bind 有界=count/回滚不重绑/多行渲染/截断/图标占位/段头/空态/自绘/焦点/fling 吸附);
全量回归 widgets/dispatch/box/anim/scroll/ime/pinyin/overlay/notif/sdk_input_keys/p1p2p3 全 PASS;
交叉 zig-mipsel -Wall -Wextra 全 SDK TU 0 warning; meow_ui.a 新 md5=2a2d8000b95dd211d09dc736d5538ad0

文档: MEOW_APP_SDK.md §5.5 同步虚拟化层(API 一览/池语义/集成/回归).
This commit is contained in:
AskaEth committed 2026-09-02 01:36:48 +08:00
1 parent 85e1d03157
commit 9d54cf89c5
4 files changed
+797 -69

No files matched your search

+46 -1
View File
@@ -372,7 +372,7 @@ int meow_ui_setform_hit_row(meow_widget *f, int x, int y);/* 命中行号(-1=
### 5.5 设计模板 A② 列表+选择 [源:2026-08-30]
> **性质**:SDK 设计模板,供 App 主页/子页按需选用;对既有 `meow_list_create`(B1 最小集,§5,仅 label 文本)做**结构化扩展**(行=图标+标题+副标题+右侧操作 + 选中态)。API「草案/待定案」,不实现。**(✅ 已实现:结构化列表控件 `W_LISTVIEW`,M2.76 · agent-186 · 243148e,见 §5.8.8 分批;长按事件 `MEOW_EV_LONG_PRESS` + `meow_ui_set_long_press_cb/ms`,M2.77 · agent-191 · e95552b。)**
> **性质**:SDK 设计模板,供 App 主页/子页按需选用;对既有 `meow_list_create`(B1 最小集,§5,仅 label 文本)做**结构化扩展**(行=图标+标题+副标题+右侧操作 + 选中态)。API「草案/待定案」,不实现。**(✅ 已实现:结构化列表控件 `W_LISTVIEW`,M2.76 · agent-186 · 243148e,见 §5.8.8 分批;长按事件 `MEOW_EV_LONG_PRESS` + `meow_ui_set_long_press_cb/ms`,M2.77 · agent-191 · e95552b;虚拟化层(固定 item 池 + 多行富 item + 完全自绘 + 段头 + 空态),2026-09-02,见 §5.5「虚拟化层」。)**
**摘要**:可滚动选择容器。**行数据源回调**逐行给出(图标 / 标题 / 副标题 / 右侧操作 / 是否可选),容器负责绘制/滚动/选中/命中;支持**单选、多选、长按**(上下文操作)。适合「已保存网络 / 附近WiFi / 蓝牙设备 / 歌曲列表 / 设置子菜单」等。
@@ -419,6 +419,51 @@ int meow_ui_listview_hit(meow_widget *lv, int x, int y); /* 命中行;
```
> 说明:既有 `meow_list_create`(label-only)保留;`meow_ui_listview_*` 为**结构化扩展**(图标/副标题/右侧/选中),可作为真则替换裸 label 列表。
#### 虚拟化层(2026-09-02,W_LISTVIEW 扩展;API 追加式,旧 API 一字不改)
> **痛点**:W_LISTVIEW(src2 每帧按需取行)只画可见行,但**每帧重取全部可见行**;大列表(几千/
> 上万首)App 只能自行造「滑动窗口」补载(如 ncm playlist.c 的 `pl_maybe_ensure` + `appstate_song_copy`)。
> 本层把「固定 item 池 + 多行富 item + 完全自绘」收编为 SDK 级能力,让 App 只提供「总数 + bind」回调。
**关键交互/数据模型**:
- **数据源**:`meow_listview_count_fn`(返回总行数,任意长 ≥65535,不常驻 item 对象)+ `meow_listview_bind_fn`
(`index, meow_lv_item*, ctx`,仅在行「进入视口」(绑定到固定池槽)时被调**一次**)。`count` 每帧实时查
(搜索过滤/懒加载动态长度)。
- **固定 item 池**:池容量 = 视口行数 + 2 静态槽(有界,`MEOW_LV_POOL_MAX`=96),行离开视口不销毁、
**回滚不重绑**(同一 index 命中同一槽 → bind 不重调);滚动只改 viewport 偏移(复用既有 set_scroll/max_scroll),
不重绑未进视口的项。**整表扫过后池发生 wrap(cap<count),回收合法重绑但每次 draw 有界(≤视口窗口)**。
- **多行富 item**:`meow_lv_item` 含 主标题 / 副标题(第二行小字)/ 左图标·缩略图 / 右尾件(chevron·开关·复选·⋯)/
`section`(段头占位行)/ `enabled`。行高可配:`set_item_h`(精确 px)或 `set_item_tier(lines)`(1→48 / 2→56)。
- **默认 renderer**(`meow_listview_set_item_renderer(lines, show_icon, show_right)`)用主题语义色绘制富 item;
**完全自绘**:`meow_listview_set_item_draw(draw_fn, ctx)` 覆盖默认 renderer(App 收 idx/rect/state 自绘整行)。
- **段头**:bind 返回 `item->section=1`(title=段名)→ 段头占位行(非粘性;粘性为后续增强)。
- **空态**:`meow_listview_set_empty_text(text)`——count==0 时视口内居中画文案。
**与既有机制集成**:焦点/事件走 §6.4(`meow_listview_tap_at` 命中行自动 `meow_ui_focus_acquire`,点外由
`meow_ui_focus_tap` 释放——list 焦点残留根治下沉);滚动接 §12.3 `meow_scroll`(`meow_scroll_wrap(lv, 1)`,
`track`+`fling` 跟手/惯性,`set_snap(item_h)` 吸附到行边界);选中/按压态样式走主题
(`primaryContainer`/半透明 `primary` 按压层);`enabled=0` 行变淡且命中不响应。
**API 一览(`include/meow_ui_widgets.h`,§5.5)**:
```c
typedef struct meow_lv_item { const char *title, *subtitle; const meow_img *icon; int icon_kind;
int right, on, enabled, section; void *user; } meow_lv_item;
typedef int (*meow_listview_count_fn)(void *ctx);
typedef void (*meow_listview_bind_fn)(int index, meow_lv_item *item, void *ctx);
typedef void (*meow_listview_draw_fn)(int idx, int x, int y, int w, int h, int state, void *ctx);
int meow_listview_set_vsource(meow_widget *lv, meow_listview_count_fn count,
meow_listview_bind_fn bind, void *ctx); /* 切 pool 模式 */
int meow_listview_set_item_renderer(meow_widget *lv, int lines, int show_icon, int show_right);
int meow_listview_set_item_tier(meow_widget *lv, int lines); /* 1→48 / 2→56 */
int meow_listview_set_item_draw(meow_widget *lv, meow_listview_draw_fn draw, void *ctx);
int meow_listview_set_empty_text(meow_widget *lv, const char *text);
```
> 兼容:既有 `meow_listview_*`(src2 模式)全部保留不动(`src2==NULL` 走既有路径);本层为叠加。
> `meow_widget` 尾部追加虚拟化字段(`calloc` 归零,安全);`meow_ui.a` 需重编,App 链新库(老 ABI 不重建名)。
> 宿主验证 `test_meow_ui_listvirt`(T1 虚拟化/bind 有界/回滚、T2 多行/截断/图标/尾件、T3 段头/空态、
> T4 自绘、T5 焦点/fling 联动)+ 全量回归 widgets/dispatch/box/anim/scroll/ime/pinyin/overlay/notif/
> sdk_input_keys/p1p2p3 全 PASS;交叉 -Wall -Wextra 0 warning。
---
### 5.6 设计模板 B③ 弹窗/对话框 [源:2026-08-30]