v60b:所有弹框统一主题色描边环 + 编辑改居中弹框 + 修名册下拉回弹吃掉悬浮栏

1)9 个浮层统一描边环(抽组件,不复制 8 遍)
   新增 components/FbSheetRing.ets:环宽 FB_RING_W=2 全工程唯一一处;
   实现是"外层 Column 铺色 + padding",不是 border(border 画在盒子内侧);
   外圆角 = 内圆角 + 环宽。简要卡/详情/编辑/日程详情/日程编辑/观影详情/影院/
   日程设置/模块设置全部改用;各浮层的环色 = 所属模块的主题色。

2)编辑从"贴底满宽 + 只有上圆角"改成居中弹框
   人员编辑与日程编辑:Stack 对齐改 Center,卡片 92% 宽 + 四角圆 + 环;
   constraintSize 留在卡片自己身上(挪到外层会让内层 Scroll().layoutWeight
   拿到 0 高度,资料区塌成一条线)。日程的日期时间选择弹层、两个删除确认框
   一并套环,避免同一次交互里出现两种形态。

3)修名册下拉到头回弹后悬浮按钮消失
   EdgeEffect.Spring 在越界松手后把内容弹回,每帧 offset>0 被当成"用户在往上滑"
   ⇒ 收起悬浮栏。判据 = 手指已抬起 + 最后一次方向是下滑 + 抬手不到 500ms;
   拦截必须排在 offset >= HIDE_AT 快路径之前(回弹第一帧位移常 >= 12vp)。

4)真机截图暴露的两个观感问题(静态检查全绿也照错)
   - Scroll().layoutWeight(1) 让短内容也撑满 maxHeight ⇒ 卡片空半屏
     (日程详情/模块设置),改为 flexShrink(1);内容本来就长的浮层不动。
   - 人员编辑"虚拟人物(还没弄清真实身份)"被卡片裁掉半句:两个小开关从
     并排 Row 改为 Flex(wrap) 换行,间距改走 margin。

验证:ArkTS 守卫 444/0;反向验证 17/17;真机 _fb_v60b_verify.py 11/0,
且关掉回弹拦截重编重装后该用例确实变红(证明测试不是假绿);
9 个浮层逐个真机截图确认。
This commit is contained in:
2026-10-19 08:29:44 +08:00
parent 7858de27e3
commit 1a67247407
11 changed files with 1120 additions and 740 deletions
@@ -0,0 +1,86 @@
/**
* 家书 FamilyBook · 浮层卡片的「主题色描边环」统一容器(鸿蒙端)
*
* 🔴 用户 2026-10-19 原话:
* 「既然弹框加了线,那就**所有弹框都加线**,编辑,也弄成弹框,加线,保持一致。」
*
* ⇒ 以前只有「简要卡」自己手写了一层环(外层 `Column` 铺色 + `padding` + 内层白卡)。
* 手写一次没问题,**手写十次必然漂移**(环宽/圆角/阴影/边距一处一个样)——
* 所以抽成这个组件:**所有浮层都套它**,环宽和圆角只在这里定义。
*
* ⚠️ 为什么是"外层铺色 + 内边距",而不是给白卡加 `border`:
* `border` 画在**盒子内侧**,会把卡片内容区撑窄 2vp,且圆角处顺着**内圆角**走,
* 看着像"白卡描了彩边";用户要的是"**外面**加一圈" ⇒ 必须垫一层。
* (`FbPersonQuickSheet` 第一版就踩过,注释里留着证据。)
*
* ⚠️ `clip(true)` 不是装饰:卡片内部有 `Scroll`(详情/编辑都很长),
* 不裁的话滚动内容会**越过圆角**画到环上,看着像"内容从卡片里漏出来"。
* 如果调用方内部还要往外"溢出显示"(如全屏图片查看器),传 `clipContent: false`
* —— 并且查看器必须放在**这个组件之外**的兄弟层(现在 `FbMovieDetailSheet` 就是这么做的)。
*
* ⚠️ 本组件只管"外观"(宽度由调用方给、内容由尾随闭包给):
* 它**不设** maxHeight / padding / 背景层次 —— 那些属于各卡片自己的版式。
*/
import { FbColors, FbMetric, FB_SHADOW, FbTint } from '../common/Theme';
/**
* 环的宽度(vp)—— **全应用唯一一处定义**。
*
* ⚠️ 2vp 是"看得见但不喧哗"的那一档:1vp 在深色遮罩上仍显得细弱(真机上像一条发丝),
* 3vp 以上就变成"彩色相框",抢了内容和按钮的注意力。
* ⚠️ 内层圆角 = `radius`,外层圆角 = `radius + 环宽`:
* 两圈同心圆角的差值必须正好等于环宽,否则环在内侧显厚、外侧显薄(看着像描边歪了)。
*/
export const FB_RING_W: number = 2;
@ComponentV2
export struct FbSheetRing {
/** 卡片(内层)圆角;环层自动 +FB_RING_W */
@Param radius: number = FbMetric.radius;
/**
* 环的颜色 —— 各模块的主题色(砖红 / 青 / 靛蓝…)。
*
* ⚠️ 必须是 **hex 字符串**(不能用 `Resource`):这里要直接当背景色用,
* 而默认值在 ArkTS 里也必须是常量表达式。
*/
@Param ringColor: string = FbTint.brand;
/**
* 阴影半径(vp)。0 = **不画阴影**。
*
* ⚠️ 嵌在别的卡片里时(顶栏「我的资料」塞进 bindSheet)要传 0:
* 宿主已经有自己的容器与投影,再叠一层会显得脏。
*/
@Param shadowRadius: number = 24;
/**
* 是否裁剪内容到圆角。
*
* 默认 `true`;只有在卡片内部还有"要溢出显示"的层时传 `false`
* (见文件头 `clip` 的说明)。
*/
@Param clipContent: boolean = true;
/** 卡片本体(尾随闭包传入) */
@BuilderParam content: () => void;
build() {
Column() {
Column() {
this.content()
}
.width('100%')
.backgroundColor(FbColors.surface)
.borderRadius(this.radius)
.clip(this.clipContent)
}
.width('100%')
.padding(FB_RING_W)
.backgroundColor(this.ringColor)
.borderRadius(this.radius + FB_RING_W)
.alignItems(HorizontalAlign.Center)
.shadow({ radius: this.shadowRadius, color: FB_SHADOW, offsetX: 0, offsetY: 6 })
}
}