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
@@ -19,8 +19,12 @@
*/
import { FbColors, FbMetric, FbIcon, fbTint, FbTint } from '../common/Theme';
import { FbSheetRing } from './FbSheetRing';
/** 贴底卡片的手势区缓冲(vp)—— 同其它浮层 */
/** 贴底卡片的手势区缓冲(vp)—— 同其它浮层
* ⚠️ 2026-10-19 起本浮层改成**居中弹框**,这个常量暂时没有引用;
* 保留它(而不是删掉)是因为"贴底浮层"这个形态本工程其它地方还在用,
* 删了以后有人要改回去还得再想一遍为什么是 16。 */
const FB_SHEET_BOTTOM_GAP: number = 16;
/** 设置菜单里的一条 */
@@ -52,46 +56,81 @@ export struct FbModuleSettingsSheet {
@Event onPick: (action: string) => void = (a: string): void => {
};
build() {
Column({ space: 0 }) {
// ---- 标题栏 ----
Row() {
Text(this.title)
.fontSize(FbMetric.fontTitle)
.fontWeight(FontWeight.Medium)
.fontColor(FbColors.ink)
.layoutWeight(1)
Text('完成')
.fontSize(FbMetric.fontSmall)
.fontColor('#4A7C82')
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.onClick((): void => {
this.onClose();
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
/**
* 卡片外圈描边环的颜色(hex,'' = 用默认品牌色)。
*
* 🔴 本组件是**通用**的(读书/观影/任务/资源…都用它)⇒ 环色由调用方传
* "那个模块的主题色";不传时用品牌砖红(至少不是灰色,不会看着像禁用)。
*/
@Param accent: string = '';
Scroll() {
Column({ space: 0 }) {
ForEach(this.items, (it: FbSettingItem) => {
this.settingRow(it)
}, (it: FbSettingItem): string => 'st_' + it.action + '_' + it.label)
/** 环色:显式给了就用给的,否则用品牌色 */
private accentColor(): string {
return this.accent !== '' ? this.accent : FbTint.brand;
}
build() {
/* 🔴 2026-10-19:与其它浮层统一成"**居中的圆角弹框 + 主题色环**"
(用户:「所有弹框都加线,保持一致」)。
⚠️ 原来是"贴底满宽 + 只有上面两个角圆",宿主 Stack 的对齐是 `Bottom`
⇒ 它看起来像一条"抽屉",加了环也只会露在屏幕顶部一条。
⚠️ 这是一个**铺满屏幕**的容器 ⇒ 必须给 `hitTestBehavior(Transparent)`:
否则它把整屏的点击都吃掉,"点空白关掉"就失效了。 */
Column() {
Column() {
FbSheetRing({ radius: FbMetric.radius, ringColor: this.accentColor() }) {
Column({ space: 0 }) {
// ---- 标题栏 ----
Row() {
Text(this.title)
.fontSize(FbMetric.fontTitle)
.fontWeight(FontWeight.Medium)
.fontColor(FbColors.ink)
.layoutWeight(1)
Text('完成')
.fontSize(FbMetric.fontSmall)
.fontColor('#4A7C82')
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.onClick((): void => {
this.onClose();
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
Scroll() {
Column({ space: 0 }) {
ForEach(this.items, (it: FbSettingItem) => {
this.settingRow(it)
}, (it: FbSettingItem): string => 'st_' + it.action + '_' + it.label)
}
.width('100%')
.padding({ top: 10 })
}
/* 🔴 2026-10-19:原来是 `Scroll().layoutWeight(1)` —— 它让滚动区**吃满剩余高度**,
于是只有 4 条菜单也会把卡片顶到 `maxHeight`(70%),
下面留一大片空白(真机截图:菜单之后空半屏)。
⇒ `flexShrink(1)`:卡片按内容自适应高,
菜单多到超过 70% 时这一块才收缩并滚动。
⚠️ 不能只删掉 `layoutWeight`:`Column` 的子项默认 `flexShrink = 0`,
不收缩 ⇒ 超长菜单会**溢出卡片**被裁掉。 */
.flexShrink(1)
.width('100%')
.scrollBar(BarState.Off)
.align(Alignment.TopStart)
}
.width('100%')
.constraintSize({ maxHeight: '70%' })
.padding({ left: 18, right: 18, top: 18, bottom: 20 })
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding({ top: 10 })
}
.layoutWeight(1)
.width('100%')
.scrollBar(BarState.Off)
.align(Alignment.TopStart)
.width('92%')
}
.width('100%')
.constraintSize({ maxHeight: '70%' })
.padding({ left: 18, right: 18, top: 18, bottom: 20 + FB_SHEET_BOTTOM_GAP })
.backgroundColor(FbColors.surface)
.borderRadius({ topLeft: FbMetric.radius, topRight: FbMetric.radius })
.alignItems(HorizontalAlign.Start)
.height('100%')
.justifyContent(FlexAlign.Center)
.hitTestBehavior(HitTestMode.Transparent)
}
/**