sdk: 事件分发形式化(§6.4)—— 统一命中/捕获/消费/层间隔离/焦点
根治「焦点/事件穿透」一类反复 bug。此前命中/捕获/消费/层间隔离各处 ad-hoc; 现上收为单一仲裁者(meow_ui_input.c),公共 API 只追加、不删改既有签名。 分发模型: - 触摸沿 z 序自顶向下命中(meow_draw_hit_topdown,owner==active+enable 过滤); - 命中即消费;模态层永远先审(meow_ui_modal_begin/end/active/depth); - down 捕获(meow_ui_gesture_begin/owner/end):命中目标捕获手势直到 up,防滑出误触下层; - 模态存在时下层完全收不到事件——hit_topdown 恒返回模态哨兵(背板消费,不透传); - meow_ui_run 在 TOUCH_DOWN 自动 begin、TAP/SWIPE/LONG_PRESS/NOTIF_PULL 自动 end。 焦点模型: - 唯一持有者(meow_ui_focus_acquire/release/owner/tap); - 点非 focus 区域→释放并通知(meow_ui_focus_tap,list 焦点残留根治); - 滚动容器(list/listview)tap_at 命中行自动 acquire,点外由 run 的 focus_tap 释放; - lost 回调(meow_ui_focus_set_lost_cb)通知转移。 迁移(行为修复,正常交互语义不变): - dialog/sheet → meow_ui_modal_begin/end(模态期下层收不到;叠黑由既有整帧快照+卡片仅重绘保证); - list/listview tap → meow_ui_focus_acquire; - 注入/叠加让位(overlay_input_suppressed)与模态层隔离互补,语义不变。 验证:新穿透矩阵 test_meow_ui_dispatch(M1 模态点下层不触发 / M2 弹层叠开两层层隔离 / M3 捕获手势滑出不误触 / M4 list 焦点点外释放)ALL PASS; 全量回归 widgets/ime_fix/pinyin/overlay_suppress/notif_gesture/sdk_fixes/sb_collapse/ p1p2p3_repro/box/anim/scroll/sdk_input_keys 全 PASS;交叉 -Wall -Wextra 0 warning。 meow_ui.a 新 md5:a9fcfb6eeb07ddbdd48039df4f8f18ce(主会话统一重链,本仓未重链 App)
This commit is contained in:
1 parent
c3abc3fee4
commit
54d2791f48
8 files changed
+428
-3
No files matched your search
@@ -878,6 +878,97 @@ void meow_ui_global_remove(int id);
|
||||
SDK 侧 `meow_ui_nav.c`/`meow_ui_media.c` 封装同步落地(**agent-206 · 9b41957**)。
|
||||
见 `FRAMEWORK_DESIGN §10.5` / `devdocs/plan/NOTIF_CENTER_APP_OVERLAY_PLAN.md`。
|
||||
|
||||
### 6.4 事件分发形式化(2026-09-02):命中测试 / 捕获 / 消费 / 层间隔离 / 唯一焦点
|
||||
|
||||
> **定位**:把此前各处 ad-hoc 的「命中/捕获/消费/层间隔离/焦点」补丁(模态穿透、弹层叠黑、
|
||||
> list 焦点残留、同坐标二次消费)**上收为单一仲裁者**。三个历史根因(设置页滑条穿透、
|
||||
> Dialog/Sheet 弹层叠黑、list 焦点残留导致主页面滑不动)与「注入事件被下层同坐标控件二次消费」
|
||||
> 都在本节模型内覆盖。**兼容铁律:只追加 API、不删改既有签名**;未调用本节 API 的 App 行为与
|
||||
> 之前完全一致(命中/捕获仍可由 App 在 `on_tap`/`on_touch_*` 自理)。hello/files/ncm/reader 等
|
||||
> 既有 App 只把 SDK 提供的语义用于**收敛 bug**,不改正常交互语义。
|
||||
|
||||
#### 6.4.1 分发模型(自上而下命中 + 命中即消费 + down 捕获 + 模态层间隔离)
|
||||
|
||||
触摸事件沿 **z 序自顶向下**命中(模态层**永远先审**);某一层命中即消费(返回 consumed 才继续
|
||||
下探)。一次 **touch-down 命中后捕获整个手势直到 up**——期间 move/up 只发给捕获目标,**防滑出后
|
||||
误触发下层**(根治「手指滑出控件仍点下层」)。**模态层存在时下层完全收不到事件**(含兜底:
|
||||
模态背板未命中的事件由背板消费,不透传)。
|
||||
|
||||
层序(顶 → 底)与 §6.1 三层模型 +0 模态层合成一张表:
|
||||
|
||||
| 层 | 命中语义 | 是否透传 |
|
||||
|---|---|---|
|
||||
| **+0 模态层**(Dialog/Sheet/通知中心/电源菜单等) | 模态始终先审;未命中的事件由**背板消费**(点外=取消/关闭) | **不透传** |
|
||||
| **③ 系统全局**(IME/状态栏/通知中心入口……已在运行循环消费) | 命中即消费 | 返回 1 才透传 |
|
||||
| **② App 跨 Activity 全局**(`meow_ui_global_hit`) | 命中返回 1=消费 | 否则落下层 |
|
||||
| **① 当前 Activity 页面控件**(view/widget,z 降序) | 命中即消费 | 否则让 App 自理 |
|
||||
|
||||
SDK 提供统一仲裁者(`meow_ui_hit_topdown` 沿 z 降序返回首个命中控件,含 `owner==active`+enable
|
||||
过滤)。**模态存在时它恒返回模态哨兵**——下层控件(即使同坐标)绝不会成为捕获/命中目标。
|
||||
|
||||
手势捕获由 `meow_ui_gesture_begin/owner/end` 表达:`meow_ui_run` 在 `MEOW_EV_TOUCH_DOWN` 时
|
||||
自动 `begin`(命中并捕获),随后 move/up 只发给捕获目标(`meow_ui_gesture_owner` 恒定),
|
||||
抬手(TAP/SWIPE/LONG_PRESS/NOTIF_PULL/清队列)自动 `end` 释放。模态期间 begin 捕获的是模态
|
||||
哨兵——下层不被捕获,天然根治穿透。
|
||||
|
||||
#### 6.4.2 焦点模型(唯一持有者 + 点外释放 + 滚动容器转移)
|
||||
|
||||
**焦点持有者唯一**(`meow_ui_focus_owner`)。点非 focus 区域 → **释放焦点并触发通知回调**
|
||||
(`meow_ui_focus_tap`,list 焦点残留根治)。滚动容器(W_LIST/W_LISTVIEW)在
|
||||
`meow_list_tap_at`/`meow_listview_tap_at` 命中行时自动 `meow_ui_focus_acquire`(列表成为唯一
|
||||
焦点);任何落在该容器外的触摸(`meow_ui_focus_tap` 判定 hit != focus owner)释放焦点并通知,
|
||||
回退到页面级滚动。
|
||||
|
||||
**滚动容器间焦点转移规则**:
|
||||
|
||||
1. 某滚动容器(list/lazycolumn/row)获得焦点后,随后的**纵向** swipe / 拖动滚动该容器;
|
||||
2. 任何命中落在该容器**外**的触摸(含空白、页面内容、其它控件)→ 焦点释放 + `lost` 回调,
|
||||
后续拖动滚动**页面**(不再滚列表);
|
||||
3. 焦点释放/转移不销毁容器控件(`meow_widget` 仍由 App/视图持有),下次命中行重新 acquire。
|
||||
|
||||
#### 6.4.3 公共 API(至 `meow_ui_input.h`,仅追加)
|
||||
|
||||
```c
|
||||
/* 模态作用域:dialog/sheet/App 自绘模态「打开时 begin、关闭时 end」;支持嵌套(depth 递增)。 */
|
||||
typedef struct meow_ui_modal meow_ui_modal;
|
||||
meow_ui_modal *meow_ui_modal_begin(void); /* 打开模态层入栈;返回句柄(NULL=栈满) */
|
||||
void meow_ui_modal_end(meow_ui_modal *m); /* 关闭:弹到 m(含)一次性关上嵌套;幂等 */
|
||||
int meow_ui_modal_active(void); /* 当前是否有任一模态作用域 */
|
||||
int meow_ui_modal_depth(void); /* 模态栈深(弹层叠开计数) */
|
||||
|
||||
/* 自上而下命中:z 降序返回首个命中控件;模态存在时恒返回模态哨兵(背板消费,不透传)。 */
|
||||
void *meow_ui_hit_topdown(int x, int y);
|
||||
int meow_ui_widget_hit(meow_widget *w, int x, int y); /* meow_widget_hit 公共别名 */
|
||||
|
||||
/* 手势捕获:down 命中即捕获直到 up;期间 move/up 只给捕获目标(滑出不误触)。 */
|
||||
void *meow_ui_gesture_begin(int x, int y);
|
||||
void *meow_ui_gesture_owner(void);
|
||||
void meow_ui_gesture_end(void);
|
||||
|
||||
/* 唯一焦点:点非 focus 区域 → 释放并通知(list 焦点残留根治)。 */
|
||||
typedef void (*meow_ui_focus_lost_fn)(void *owner, void *ctx);
|
||||
void meow_ui_focus_set_lost_cb(meow_ui_focus_lost_fn cb, void *ctx);
|
||||
void *meow_ui_focus_owner(void);
|
||||
int meow_ui_focus_acquire(void *owner);
|
||||
int meow_ui_focus_release(void *owner);
|
||||
void meow_ui_focus_tap(int x, int y);
|
||||
```
|
||||
|
||||
#### 6.4.4 迁移与兼容
|
||||
|
||||
- **dialog/sheet**(`meow_ui_dialog.c`):`meow_dialog_show`/`meow_sheet_open` 已迁到
|
||||
`meow_ui_modal_begin/end`——模态打开期间 `meow_ui_modal_active()` 为真,下层收不到触摸;
|
||||
点卡片外由背板消费(关闭)。**弹层叠黑**由既有「打开前整帧快照 + 关闭还原 + 高亮仅重绘卡片
|
||||
不叠遮罩」保证(M2.71-bug3),与本节模态层隔离正交、互不影响。
|
||||
- **list/scroll**(`meow_ui_widget.c`):`meow_list_tap_at`/`meow_listview_tap_at` 命中行自动
|
||||
`meow_ui_focus_acquire`,点外由 `meow_ui_run` 的 `meow_ui_focus_tap` 统一释放——list 焦点残留
|
||||
根治下沉到 SDK;App 层不再需要各自「点非 list 区域手动清 focus」补丁。
|
||||
- **注入/叠加让位**:`overlay_input_suppressed`(§10.5)是**系统叠加层**的层间隔离(面板输入由
|
||||
launcher 接管、App 排空副本),与本节模态层隔离互补共同防「同坐标二次消费」,语义不变。
|
||||
- 以上均为**行为收敛**(修 bug),正常交互语义不变;`p1p2p3_repro`/`widgets`/`ime_fix`/`pinyin`/
|
||||
`overlay_suppress`/`notif_gesture`/`sdk_fixes`/`sb_collapse`/`box`/`anim`/`scroll`/`sdk_input_keys`
|
||||
全量回归通过。
|
||||
|
||||
---
|
||||
|
||||
## 7. 动画/时间(B1 最小可用)
|
||||
|
||||
Reference in new issue
Block a user