SDK 冲刺批①+②+⑤: meow_box 线性布局 + meow_anim 动画基座 + meow_scroll 滚动物理

- meow_box(include/meow_ui_box.h + meow_ui_box.c):竖直/水平容器;子项=固定|weight|wrap;
  margin/padding/gap;主轴对齐 start/center/end/space-between/around/evenly;交叉轴 start/center/end/stretch;
  嵌套(深度≤16 静态栈,单遍求解,无递归爆炸)。可作 meow_view 布局提供者
  (meow_view_set_layout/relayout,opt-in;未设布局的 view 保持现有绝对坐标行为)。
  新增 meow_widget_set_rect(只写字段不标脏)作为 box 写坐标的通道。
- meow_anim(include/meow_ui_anim.h + meow_ui_anim.c):时间驱动 tween(from/to/duration/easing:
  linear/ease-out/ease-in-out/overshoot)+ update/done 回调;静态池≤16、取消、并行多动画;
  meow_anim_set_region 让每帧只 flush 动画影响区(不整屏)。meow_anim_tick 挂主循环 on_tick,
  无动画零开销(只查计数即返回)。
- meow_scroll(include/meow_ui_scroll.h + meow_ui_scroll.c):速度跟踪(最近 N 采样加权)+ 松手 fling
  (减速度曲线,用 anim 基座驱动)+ 边界过冲 clamp + 简单回弹(不做 spring)+ 可选 snap;
  跟手拖动行为不变(track 内部调既有 set_scroll);每帧只 redraw 列表视口区;不引 libm。
- 追加式:既有 meow_row/column/box 与全部 meow_*_create/hit/scroll 签名一行未改;旧绝对坐标永远有效;
  既有 App 免改源码。
- 验证:宿主新测试 box(42)/anim(32)/scroll(17) 全 PASS;既存 9 回归(widgets/sdk_input_keys/ime_fix/
  pinyin/overlay_suppress/notif_gesture/sdk_fixes/sb_collapse/p1p2p3_repro)全 PASS;
  离屏 demo(demo_box_scroll.c)渲染 box 布局 + 列表 fling 正常;zig-mipsel -Wall -Wextra 全 TU 0 warning;
  meow_ui.a md5 83dd6a2d0d24cc748a8659c29f1de2b5(未重链/部署 hello/files/ncm/reader,由主会话统一处理)。
This commit is contained in:
MeowOS committed 2026-09-01 23:49:24 +08:00
1 parent 553a7d5d9e
commit 5a5e995ebd
19 files changed
+1839 -2

No files matched your search

+75
View File
@@ -0,0 +1,75 @@
/*
* meow_ui_anim.h — SDK 动画基座 + UI 节拍器(§12.2:meow_anim / meow_anim_tick)。
*
* 定位:给应用提供**时间驱动 tween**(from/to/duration/easing)+ 完成/取消回调,并行多动画
* (静态池≤MEOW_ANIM_MAX)+ 与脏区集成(动画帧只标动画影响区,不做整屏重绘)。
*
* 节拍:**挂既有 on_tick 机制**(meow_ui_run 主循环 / meow_ui_feed_tick 阻塞 IME 循环),
* 无常驻高频轮询;无动画时 meow_anim_tick() 只做一个计数检查即返回(零开销)。
*
* 内存纪律:静态池(≤MEOW_ANIM_MAX),start/cancel/tick 全程零 malloc。
*
* 与 §7 的关系:§7(B1 最小可用)是「应用自己在 on_tick 里用 meow_ui_time_ms 做时间轴」;
* 本模块把这件事收敛成声明式 tween 对象 + 结束回调,是 §7 的**正式基座**(应用可任选其一或混用)。
*/
#ifndef MEOW_UI_ANIM_H
#define MEOW_UI_ANIM_H
#include "meow_ui_types.h" /* 基础类型(子头不引伞头,避免相对路径依赖) */
#ifdef __cplusplus
extern "C" {
#endif
/* ---- 缓动曲线(t∈[0,1] → 曲线化的进度;OVERSHOOT 在中后段可略>1、末点恰=1)---- */
typedef enum {
MEOW_EASE_LINEAR = 0,
MEOW_EASE_OUT = 1, /* 快进慢停(decelerate) */
MEOW_EASE_IN_OUT = 2, /* 慢入慢出 */
MEOW_EASE_OVERSHOOT = 3, /* 越过目标再回稳(小回弹) */
} meow_ease;
float meow_ease_apply(meow_ease e, float t);
/* ---- 动画对象(不透明句柄;静态池)---- */
#define MEOW_ANIM_MAX 16
typedef struct meow_anim meow_anim;
/* 每帧回调:v = 当前插值值(from + (to-from)*ease(t))。app 在此更新状态并绘制。 */
typedef void (*meow_anim_update_fn)(meow_anim *a, float v, void *ctx);
/* 完成/取消回调:canceled=1=被取消,0=自然完成。 */
typedef void (*meow_anim_done_fn)(meow_anim *a, int canceled, void *ctx);
typedef struct meow_anim_desc {
float from;
float to;
uint32_t duration_ms; /* 时长(ms);0 视为瞬发(下一 tick 完成) */
meow_ease ease;
meow_anim_update_fn update; /* 可 NULL */
meow_anim_done_fn done; /* 可 NULL */
void *ctx;
} meow_anim_desc;
/* 启动一个动画(空闲槽;池满返回 NULL)。start 即置 value=from 并回调一次 update(0)。 */
meow_anim *meow_anim_start(const meow_anim_desc *d);
/* 取消(触发 done(canceled=1),不再 update)。 */
void meow_anim_cancel(meow_anim *a);
/* 查询:仍在运行(value 未达终点)。 */
int meow_anim_active(meow_anim *a);
/* 查询:当前插值值。 */
float meow_anim_value(meow_anim *a);
/* 与脏区集成:动画每 tick 只 flush 影响区(x,y,w,h;x<0 表示不自动 flush)。
* app 的 update 回调通常也会用 meow_ui_flush_region 自刷;设了这个则 tick 自动刷一次,
* 保证「动画帧只标脏动画影响区,不整屏」。 */
void meow_anim_set_region(meow_anim *a, int x, int y, int w, int h);
/* ---- 节拍器(挂在 on_tick / meow_ui_feed_tick;无动画零开销)---- */
void meow_anim_tick(void); /* 推进所有活动动画(完成/取消在内部处理) */
unsigned meow_anim_count(void); /* 活动动画数(0=空闲) */
#ifdef __cplusplus
}
#endif
#endif /* MEOW_UI_ANIM_H */