跨端: 修「输入框打开时回复球还在上面」——正是 morph 缺掉的那半截
用户:「你的图标变成输入框,图标变成邮件的动画呢?」
## 真 bug:球没有 `if`,一直挂在树上
实测证据(宽屏 3184,点球打开回复条后抓图):
底层面板已展开(「回复给 pi@root.realtext」+ 输入框 + 取消/发送),
而**蓝球仍然浮在它上方** —— 测得蓝块 `x 2948..3104 y 1500..1628`,
1008 个蓝像素。球不但与「发送」抢同一块地方,还压住输入框右端。
WebUI 是 `if (!open) return <button ... />`(`MailView.tsx:990`)——
**收起态才渲染球**。点开时球从 DOM 消失,才有"球长成输入框"。
## 讽刺的是:注释写的就是对的,代码没跟上
我 2026-09-21 加 morph 时在那段注释里写的是:
`follow: true` 是给"if 范式下**始终在组件树上**的组件"用的;
我们这两端是 `if/else` 互斥出现(一端在树上时另一端不在),
所以用默认 `follow: false`。
——「互斥出现」。可球那一端**根本没有 `if`**。
⇒ `geometryTransition` 的 out 端从未消失:
· 视觉上:球压在展开的面板上(上面的截图);
· 动画上:没有"球这个形态结束"的那一刻,morph 只剩 in 端在动,
用户看到的就不是"图标变成输入框",而是"球还在,下面忽然多了个框"。
★ 教训:`geometryTransition` 的契约是"**两个**组件、一个 in 一个 out"。
我按契约写了注释,却没按契约写代码 —— 而注释不会报错。
这类"文档与实现分叉"只有**在设备上看一眼**才抓得到。
修:`if (!this.showReplyBox && !this.showForwardBox) { ... }`
(转发条也占底部同一块地方,所以两个条件都要)。
## 验证
✓ 设备实测:打开回复条后**蓝球已消失**(同一段像素扫描,0 个蓝像素)
✓ 探针复测 morph 中间帧:把 `Motion.durMorph` 临时改成 6000ms 后连拍 5 帧,
面板顶边 y = **2201 → 1707 → 1679 → 1679 → 1679**
⇒ 中间帧真实存在,不是"瞬移"(改回 220ms 后重新编译安装)
✓ 编译通过、无新 jscrash
✗ 未验证:220ms 原始时长下的**观感**——抓图往返 1.5-3s,探针比被测对象
慢一个数量级(同 `harmony-morph-unverified-middleframes`)。
只能说"动画在播且播的是几何形变",不能说"220ms 手感对"。
This commit is contained in:
@ -1208,13 +1208,35 @@ export struct MailDetailView {
|
||||
* 转发用描边球(`surfaceMuted` 底 + 品牌色图标)—— 两个实心球并排
|
||||
* 会让人分不出哪个更主要。
|
||||
*/
|
||||
Row({ space: 12 }) {
|
||||
Button() {
|
||||
AmIcon({ iconName: 'chatBubble', iconSize: 24, iconColor: Theme.accentFg })
|
||||
}
|
||||
.width(56).height(56)
|
||||
.borderRadius(28)
|
||||
.backgroundColor(Theme.accent)
|
||||
/*
|
||||
* ★★ 2026-09-21 修(真 bug,设备实测撞出来的):**球在输入框打开时必须消失**。
|
||||
*
|
||||
* 实测证据:点球打开回复条后抓图,底层面板已经展开
|
||||
*(「回复给 pi@root.realtext」+ 输入框 + 取消/发送),
|
||||
* 而**蓝球仍然浮在它上方**(测得蓝块 `x 2948..3104 y 1500..1628`,1008 个蓝像素)——
|
||||
* 球和「发送」按钮抢同一块地方,球还压住了输入框右端。
|
||||
*
|
||||
* WebUI 是 `if (!open) return <button .../>`(`MailView.tsx:990`)——
|
||||
* **收起态才渲染球**。
|
||||
*
|
||||
* 而且这**恰好是上面那段注释写明的形态**:
|
||||
* 「这两端是 `if/else` 互斥出现(一端在树上时另一端不在),
|
||||
* 所以用默认 `follow: false`」
|
||||
* ——可球原来根本**没有 `if`**,一直挂在树上。
|
||||
* 即:注释描述的是正确设计,代码没跟上。
|
||||
* ⇒ `geometryTransition` 缺了 out 端的消失,morph 也就没有"从球长出来"
|
||||
* 那半截(用户说"图标变成输入框的动画呢"——这就是原因之一)。
|
||||
*
|
||||
* 两个弹层任一打开都要藏球(转发条也占底部同一块地方)。
|
||||
*/
|
||||
if (!this.showReplyBox && !this.showForwardBox) {
|
||||
Row({ space: 12 }) {
|
||||
Button() {
|
||||
AmIcon({ iconName: 'chatBubble', iconSize: 24, iconColor: Theme.accentFg })
|
||||
}
|
||||
.width(56).height(56)
|
||||
.borderRadius(28)
|
||||
.backgroundColor(Theme.accent)
|
||||
/*
|
||||
* ★★ 2026-09-21 加**共享元素转场**(用户:「webui 行为是按钮变成
|
||||
* 对应的写邮件页面或输入框吧,你做的啥?」)。
|
||||
@ -1250,10 +1272,11 @@ export struct MailDetailView {
|
||||
*/
|
||||
.geometryTransition('reply-morph')
|
||||
.onClick(() => { this.openReplyWithMorph(); })
|
||||
}
|
||||
.alignItems(VerticalAlign.Bottom)
|
||||
/* 让出底部悬浮条(右下只剩这一个回复球,与 WebUI `reply-fab` 同位) */
|
||||
.margin({ right: 16, bottom: this.navReserve + 16 })
|
||||
}
|
||||
.alignItems(VerticalAlign.Bottom)
|
||||
/* 让出底部悬浮条(右下只剩这一个回复球,与 WebUI `reply-fab` 同位) */
|
||||
.margin({ right: 16, bottom: this.navReserve + 16 })
|
||||
}
|
||||
.width('100%').layoutWeight(1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user