弹框动画丝滑化:入场加位移+弹簧曲线,修加载态打断动画 (#82)

用户:首页,弹出所有弹框,动画,都要改一下,改的跟丝滑流畅,
尤其是观影,基本上没动画,都需要修改。

先核实:把时长临时放大到 3s 后连拍,遮罩 246→210→170→153→148 逐帧压暗,
说明**动画确实在播**。所以不是没接上,而是动效本身太弱:
220ms 太短、只有 0.94→1 缩放(差 6%,且无方向感)、FastOutSlowIn 落定硬停、
进出同长。

四处改动:
① 入场加纵向位移 SHEET_RISE_VP=22 —— 竖向是人眼最敏感的方向,
   纯缩放读不出从哪来;22vp 是看得出从下面来但不觉得它飞了的量。
② 时长分离:卡片 320/200、遮罩 240/160(出场必须比入场快,
   用户已决定关闭,等待就是拦他);缩放起点 0.94→0.90。
③ 曲线换物理弹簧 curves.springCurve(0, 1, 228, 26)(末段自然收敛)。
   ⚠️ 先写的 Curve.springMotion 编译失败——本工程 SDK 6.1.1 里没这个 API,
      技能包速查表也把它列在高频臆造 API里,是我没照表走。
④ 观影/日程详情卡加载态:**这是观影没动画的真凶** ——
   卡片高度按内容定,加载态只有一行字(~100px),详情回来瞬间撑到 72% 屏高,
   320ms 的入场动画只播了前 1/3 就被高度突变打断。
   改法:加载态放固定 460vp 骨架屏(FbEventSheet 同样问题,一并修 300vp)。
   用固定 vp 而非 %:builder 在 Scroll 里,百分比拿不到基准。

验证(真机):放大时长连拍 N2 卡片顶边 y=1073 → N3 y=1011,
上移 62px≈20vp,证实位移生效;临时给接口加 1.5s 延迟后抓图,
骨架屏(海报位+4 条文字条)正确撑住卡片高度;临时代码已撤除(grep 0 处)。
连开合 3 轮均正常、无 JS 崩溃、进程存活。
hvigorw assembleHap BUILD SUCCESSFUL。
FbAnim 是全站唯一动画入口,98 处引用 / 14 个页面,全部同时生效。
This commit is contained in:
2026-11-06 10:18:22 +08:00
parent b0e12f14fe
commit 0f22aef689
3 changed files with 242 additions and 39 deletions
+17 -5
View File
@@ -370,15 +370,27 @@ export struct FbEventSheet {
.margin({ top: 12, bottom: 4 })
if (this.loading) {
Row({ space: 8 }) {
LoadingProgress().width(18).height(18).color(FbColors.faint)
Text('正在读取…')
.fontSize(FbMetric.fontSmall)
.fontColor(FbColors.faint)
/* 🔴 2026-11-06:加载态要给足高度,别只放一行「正在读取…」。
用户反馈"弹框动画不丝滑"。原因同 `FbMovieDetailSheet`:
卡片高度按内容定,加载态只有一行字 ⇒ 卡片很矮;
数据回来立刻撑成满屏,**入场动画被高度突变打断**。
⇒ 用骨架块占住常规高度,动画期间尺寸基本恒定。
⚠️ 固定 vp 而不是百分比:这里渲染在 Scroll 里,
Scroll 高度按内容定,百分比拿不到基准。 */
Column({ space: 12 }) {
ForEach([0, 1, 2, 3], (i: number) => {
Column()
.width(i === 1 ? '82%' : (i === 2 ? '88%' : (i === 0 ? '44%' : '60%')))
.height(i === 0 ? 18 : 12)
.borderRadius(6)
.backgroundColor(FbColors.inputBg)
}, (i: number): string => 'evsk_' + i.toString())
}
.width('100%')
.height(300)
.padding({ top: 20, bottom: 20 })
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
} else if (this.event === null) {
// 正常情况下不会走到这里(`openEvent` 一定会垫一份壳);
// 只有"打开浮层时状态被清掉"这种瞬时态才可能空着 ——
@@ -294,14 +294,43 @@ export struct FbMovieDetailSheet {
.padding({ top: 40, bottom: 40 })
.justifyContent(FlexAlign.Center)
} else if (this.loading || this.detail === null) {
Row() {
Text('正在加载详情…')
.fontSize(FbMetric.fontSmall)
.fontColor(FbColors.faint)
/* 🔴 2026-11-06:**加载态要占住卡片的常规高度**,不能只放一行字。
用户说「观影基本上没动画」。核实后原因是:
卡片高度是"按内容"的(`maxHeight: 72%` 只是上限),
加载态只有一行「正在加载详情…」⇒ 卡片约 100px 高;
详情一回来,内容把卡片瞬间撑到 72% 屏高。
入场动画(320ms 淡入+放大+上浮)只播了前 1/3 就被这次
**高度突变**打断 —— 用户看到的就是"闪一下就变满",没有动画感。
⇒ 加载态放**固定 460vp** 的骨架(约等于这条卡详情态的常见高度),
让动画期间尺寸基本恒定;内容回来只是把里面换掉,不再整卡重排。
⚠️ 为什么用固定 vp 而不是 `height('100%')`:
这个 builder 渲染在 `Scroll` 里,Scroll 的高度是"按内容"的,
百分比高度拿不到确定基准 ⇒ 会退化成一像素或直接不渲染。
固定值是这个结构下唯一可靠的选择(与本文件其它地方的取舍一致)。
⚠️ 460 的依据:详情态常见内容(海报 140 + 片名/时间/评分 + 影院 +
简介 3~5 行 + 照片一行 + 评价区标题)大约 430~500vp,
取中间值,两侧都不会有明显跳变。 */
Column({ space: 12 }) {
/* 骨架块:比一行灰字更像"内容正在来",也把高度撑住 */
Column()
.width(96)
.height(128)
.borderRadius(FbMetric.radiusS)
.backgroundColor(FbColors.inputBg)
ForEach([0, 1, 2, 3], (i: number) => {
Column()
.width(i === 0 ? '40%' : (i === 1 ? '78%' : (i === 2 ? '86%' : '58%')))
.height(i === 0 ? 16 : 11)
.borderRadius(6)
.backgroundColor(FbColors.inputBg)
.margin({ top: i === 0 ? 6 : 0 })
}, (i: number): string => 'sk_' + i.toString())
}
.width('100%')
.padding({ top: 40, bottom: 40 })
.height(460)
.padding({ top: 24, bottom: 24 })
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
} else {
this.body(this.detail)
}