v64b:修真机弹层"点了没反应"(根容器 Column → Stack)+ 日期行热区

四个日期/选择类浮层在真机上**完全打不开**:编译无告警、`aboutToAppear` 照常调用、
`dumpLayout` 里连弹层一个节点都看不到、点它会"穿透"到底下的列表。

根因(逐层二分定位):根容器写成 `Column` 且里面**先排一个整高遮罩**
(`Column().width('100%').height('100%').backgroundColor(FB_MASK)`)再排卡片。
`Column` 是**线性**布局 ⇒ 遮罩占满整高后,卡片被排到屏幕**外面**。
⇒ 全屏遮罩与卡片要"叠"(`Stack`),不能"排"(`Column`)。

改动:
- FbDateTimeField / FbCinemaPickSheet / FbPersonPickSheet:根容器改
  `Stack({ alignContent: Alignment.Center })`,遮罩与卡片作并列子项叠放;
  去掉原先用于"居中卡片"的 `justifyContent(FlexAlign.Center)`(Stack 已对齐)。
- FbDateTimeField:「日期行」的 `.onClick` 由内层 `layoutWeight(1)` 的 Row
  挪到**根 Row** —— 挂内层时那一行会被表单所在的**两列容器**盖住,
  点击穿透到底下的观影列表(表现为"点日期行,列表反而响应了")。
- FbSheetClose:`onClose` 由 `@Param` 改 `@Event`(语义归位;实测 `@Param`
  声明回调**并不会失效**,✕ 一直是能点的 —— 这不是本轮 bug 的根因,别混为一谈)。

验证:
- 构建 BUILD SUCCESSFUL;
- 静态守卫 644/0(新增 8 条:三个组件的 Stack 叠放 + 整高遮罩非空转 +
  全项目无"根 Column 先排整高遮罩"坏形态 + 日期行热区在根 Row);
- 守卫反向验证 92/0(新增 6 条注入,含把根 Stack 改回 Column、删遮罩、
  热区挪回内层,逐条证明断言真会红)。
This commit is contained in:
2026-10-20 08:55:27 +08:00
parent 8146aab1a7
commit 3b7238a418
4 changed files with 53 additions and 16 deletions
@@ -80,8 +80,12 @@ export struct FbCinemaPickSheet {
} }
build() { build() {
// 整屏遮罩 + 居中卡片(与全应用浮层同一形态) /* 🔴🔴 必须是 `Stack`,**不能**是 `Column`(2026-10-20 真机实测的真 bug)。
Column() { `Column` 是**线性**布局:全屏遮罩(100% 高)会占满整高,
卡片被排到它**下面** ⇒ 落到屏幕之外 ⇒ 弹层"点了没反应"。
症状:编译无告警、dumpLayout 里看不到弹层任何节点、点击会穿透到下层。
⇒ **全屏遮罩与卡片要"叠"(Stack),不能"排"(Column)**。 */
Stack({ alignContent: Alignment.Center }) {
Column() Column()
.width('100%') .width('100%')
.height('100%') .height('100%')
@@ -181,7 +185,6 @@ export struct FbCinemaPickSheet {
} }
.width('100%') .width('100%')
.height('100%') .height('100%')
.justifyContent(FlexAlign.Center)
.hitTestBehavior(HitTestMode.Transparent) .hitTestBehavior(HitTestMode.Transparent)
} }
@@ -131,13 +131,21 @@ export struct FbDateTimeRow {
}; };
build() { build() {
/*
* ⚠️ `.onClick` 挂在**根 `Row`** 上(整行可点),不是挂在里面那个
* `layoutWeight(1)` 的 `Row` 上 —— 2026-10-20 真机实测:
* 挂内层时,那一行会被表单所在的**两列容器**(dump 里两个
* `x1=50..521 / 559..1030、y1=602..1500` 的可点节点)盖住,
* 点击**穿透**到底下的观影列表(表现为"点日期行,列表反而响应了")。
* 根 `Row`(`.width('100%')`)与 `FbCalOptionRow` 同一形态,热区完整。
*/
Row({ space: 10 }) { Row({ space: 10 }) {
Text(this.label) Text(this.label)
.fontSize(FbMetric.fontTiny) .fontSize(FbMetric.fontTiny)
.fontColor(FbColors.faint) .fontColor(FbColors.faint)
.width(28) .width(28)
// 整块可点:日期与时间在**同一个控件**里,中间不再分两块 // 日期与时间在**同一个控件**里,中间不再分两块
Row() { Row() {
Text(fbCnDate(this.date)) Text(fbCnDate(this.date))
.fontSize(FbMetric.fontSmall) .fontSize(FbMetric.fontSmall)
@@ -155,9 +163,6 @@ export struct FbDateTimeRow {
.backgroundColor(FbColors.inputBg) .backgroundColor(FbColors.inputBg)
.borderRadius(FbMetric.radiusS) .borderRadius(FbMetric.radiusS)
.alignItems(VerticalAlign.Center) .alignItems(VerticalAlign.Center)
.onClick((): void => {
this.onTap();
})
// 右侧小箭头:暗示"点开会选" // 右侧小箭头:暗示"点开会选"
Text('›') Text('›')
@@ -166,6 +171,9 @@ export struct FbDateTimeRow {
} }
.width('100%') .width('100%')
.alignItems(VerticalAlign.Center) .alignItems(VerticalAlign.Center)
.onClick((): void => {
this.onTap();
})
} }
} }
@@ -209,7 +217,27 @@ export struct FbDateTimePicker {
} }
build() { build() {
Column() { /*
* 🔴🔴 必须是 `Stack`,**不能**是 `Column`(2026-10-20 真机实测抓到的真 bug)。
*
* 错误形态(原先):
* Column() { // 根:线性布局
* Column().width('100%').height('100%') // ← 全屏遮罩
* Column() { ...卡片... } // ← 被挤到屏幕外
* }
* `Column` 是**线性**布局:遮罩占满整高之后,卡片只能排在它**下面**,
* 于是落到屏幕之外 —— 弹层"点了没反应"。
*
* 症状极具误导性(本轮排查花了很久,逐条记下):
* · 编译通过、无告警;`aboutToAppear` **确实被调用**(组件实例化了);
* · `dumpLayout` 里**完全看不到**弹层的任何节点(连插桩的 30 号红字都没有);
* · 点日期行会"穿透"到底下的观影列表(因为卡片不在屏幕内,点到的其实是列表);
* · 同文件的 `FbDateTimeRow`(没有遮罩)一直正常 —— 差异只在遮罩这一层。
* ⇒ 教训:**全屏遮罩与卡片要"叠"(Stack),不能"排"(Column)**。
* 项目里能用的浮层(`FbMovieInsightSheet`、`FbMovieDetailSheet`)都是
* `Column{ 卡片 }` 或 `Stack{ ... }`,**没有**把全屏遮罩当 Column 子项排的。
*/
Stack({ alignContent: Alignment.Center }) {
// 遮罩:整屏铺一层,点它 = 取消。 // 遮罩:整屏铺一层,点它 = 取消。
// ⚠️ 必须**有**遮罩:没有的话,点弹层外面会直接点到下面那张编辑卡片上 // ⚠️ 必须**有**遮罩:没有的话,点弹层外面会直接点到下面那张编辑卡片上
// (真机上表现为"随手一点,表单被改了")。 // (真机上表现为"随手一点,表单被改了")。
@@ -302,8 +330,6 @@ export struct FbDateTimePicker {
} }
.width('100%') .width('100%')
.height('100%') .height('100%')
.justifyContent(FlexAlign.Center)
// ⚠️ 透明命中:让点击"卡片以外的区域"落到上面那层遮罩上(点遮罩关掉)
.hitTestBehavior(HitTestMode.Transparent) .hitTestBehavior(HitTestMode.Transparent)
} }
@@ -144,7 +144,11 @@ export struct FbPersonPickSheet {
} }
build() { build() {
Column() { /* 🔴🔴 必须是 `Stack`,**不能**是 `Column`(2026-10-20 真机实测的真 bug)。
原因与 `FbCinemaPickSheet` 那段完全相同:`Column` 是线性布局,
全屏遮罩会占满整高、把卡片挤到屏幕外 ⇒ 弹层"点了没反应"。
⇒ **全屏遮罩与卡片要"叠"(Stack),不能"排"(Column)**。 */
Stack({ alignContent: Alignment.Center }) {
Column() Column()
.width('100%') .width('100%')
.height('100%') .height('100%')
@@ -350,7 +354,6 @@ export struct FbPersonPickSheet {
} }
.width('100%') .width('100%')
.height('100%') .height('100%')
.justifyContent(FlexAlign.Center)
.hitTestBehavior(HitTestMode.Transparent) .hitTestBehavior(HitTestMode.Transparent)
} }
} }
@@ -31,10 +31,14 @@ export struct FbSheetClose {
/** /**
* 关掉浮层。 * 关掉浮层。
* *
* ⚠️ 必传:`@Param` 给不了函数默认值(ArkTS 里函数类型不能用常量表达式初始化), * 用 `@Event`:`@ComponentV2` 里回调**一律**用 `@Event`(数据入参才用 `@Param`,
* 所以这里用必填 + 各调用点都显式给。 * 见 `FbCalOptionRow.onPick` 等)。原先写的是 `@Param` ——
* ⚠️ 实测(2026-10-20 真机)`@Param` 声明回调**并不会失效**(✕ 是能点的),
* 所以这不是 bug;改过来只是**把语义摆正**,别让下一个人以为它会失效。
* 本轮真正导致"弹层点了没反应"的是**根容器 `Column` → `Stack`**
* (线性布局把卡片挤出屏幕),与本文件无关,别混为一谈。
*/ */
@Param onClose: () => void = (): void => {}; @Event onClose: () => void = (): void => {};
/** /**
* 图标的颜色。 * 图标的颜色。
@@ -92,7 +96,8 @@ export struct FbSheetTitleBar {
@Param confirmText: string = ''; @Param confirmText: string = '';
/** 主题色(标题下的副标题、确认文字用它) */ /** 主题色(标题下的副标题、确认文字用它) */
@Param accent: string = ''; @Param accent: string = '';
@Param onClose: () => void = (): void => {}; /** 同上:回调统一 `@Event`(`@Param` 实测也能用,但语义不对) */
@Event onClose: () => void = (): void => {};
build() { build() {
Row({ space: 8 }) { Row({ space: 8 }) {