diff --git a/entry/src/main/ets/components/FbPersonSheet.ets b/entry/src/main/ets/components/FbPersonSheet.ets index 1c8b03c..7ee0864 100644 --- a/entry/src/main/ets/components/FbPersonSheet.ets +++ b/entry/src/main/ets/components/FbPersonSheet.ets @@ -56,6 +56,27 @@ export struct FbPersonSheet { */ @Event onEdit: () => void = (): void => { }; + /** + * 嵌入模式:宿主**自己已经是浮层**(如 `bindSheet`)时为 true。 + * + * 🔴🔴 为什么必须有这个开关(2026-10-18 真机踩出来的真 bug): + * 本组件的根节点是 `Column().width('100%').height('100%')`(**铺满全屏**、 + * 内部再垂直居中那张 92% 宽的卡)—— 因为它的设计宿主是 + * "页面里叠一层遮罩 + Stack 居中"(名册页就是这么用的)。 + * + * 而顶栏点头像想复用这个组件时,我把它塞进了 `bindSheet`: + * **sheet 要做"高度自适应内容"(`SheetSize.FIT_CONTENT`), + * 内容却要求"铺满 100% 高度"** ⇒ 测量互相打架。 + * 真机症状:**每次点击 `AceSheet` 都创建了,却紧接着 + * `AceDrag: Drag gesture has been canceled` —— 浮层起来立刻被关掉** + * (界面看上去"点了没反应",最容易被误判成"点击没接上")。 + * + * ⇒ `embedded = true` 时:去掉 `width/height 100%` 与内层居中, + * 只留那张卡(宽度交给 sheet、高度自适应),sheet 自己负责 + * 底部手势区与遮罩。 + * ⚠️ 默认 `false` = 老行为,**名册/日程那几个调用点一个字都不用改**。 + */ + @Param embedded: boolean = false; /** 一行的图标资源 */ private iconOf(name: string): Resource { @@ -465,17 +486,29 @@ export struct FbPersonSheet { // **不要让它左右充满整个屏幕,下面也不要挨着屏幕**, // 而是放在**屏幕中间**,采用**圆角浮窗**式的形式。」 // ⇒ 不再贴底满宽:左右留边(92%)、四角圆角、垂直居中(由宿主的 Stack 对齐)。 - .width('92%') + // + // ⚠️ `embedded`(宿主自己就是 sheet)时宽度交给 sheet 决定 —— + // 再用 92% 会在 sheet 里又缩一次,看上去"卡片比容器窄一圈"。 + .width(this.embedded ? 'auto' : '92%') // 最多占屏幕 72%:上方留出可见列表,暗示"这是浮层、下面还有内容" - .constraintSize({ maxHeight: '72%' }) - .padding({ left: 18, right: 18, top: 18, bottom: 20 + FB_SHEET_BOTTOM_GAP }) + .constraintSize({ maxHeight: this.embedded ? '100%' : '72%' }) + // ⚠️ embedded 时**去掉底部手势区那段留白**:那 16 是给 + // "贴底遮罩 + 隐藏手势条"的场景补的(见 FB_SHEET_BOTTOM_GAP), + // 而 bindSheet 自己已经把手势区让出来了 ⇒ 再补就是白白多一截空白。 + .padding({ + left: 18, right: 18, top: 18, + bottom: this.embedded ? 20 : 20 + FB_SHEET_BOTTOM_GAP + }) .backgroundColor(FbColors.surface) .borderRadius(FbMetric.radius) .alignItems(HorizontalAlign.Start) } - .width('100%') - .height('100%') - .justifyContent(FlexAlign.Center) + /* 🔴 embedded(宿主自己就是 sheet)时**不能再铺满 + 居中**: + 内容是"按自适应高度"交给 sheet 的,铺 100% 高会与 + `SheetSize.FIT_CONTENT` 互相打架 ⇒ 浮层起来立刻被关(真机实测)。 */ + .width(this.embedded ? 'auto' : '100%') + .height(this.embedded ? 'auto' : '100%') + .justifyContent(this.embedded ? FlexAlign.Start : FlexAlign.Center) .hitTestBehavior(HitTestMode.Transparent) } } \ No newline at end of file diff --git a/entry/src/main/ets/components/TopBar.ets b/entry/src/main/ets/components/TopBar.ets index 2b25659..5e92a74 100644 --- a/entry/src/main/ets/components/TopBar.ets +++ b/entry/src/main/ets/components/TopBar.ets @@ -243,7 +243,10 @@ export struct FbTopBar { // ⚠️ `onDisappear` 必须复位 `myDetailSheet`(点遮罩/下滑关闭都会走它), // 否则下次点头像**打不开**(状态位还是 true 但面板已经不在)。 .bindSheet(this.myDetailSheet, this.myDetailPanel(), { - height: SheetSize.FIT_CONTENT, + // ⚠️ 用 `LARGE`(= 大高度、内容自适应)而不是 `FIT_CONTENT`: + // 详情卡片有 `maxHeight: '72%'` 的内部约束,FIT_CONTENT 下 + // 系统会试图把 sheet 压到"刚好包住内容",与那个百分比约束打架。 + height: SheetSize.LARGE, dragBar: true, showClose: false, backgroundColor: FbColors.surface, @@ -376,6 +379,14 @@ export struct FbTopBar { } else if (this.myDetail !== null) { FbPersonSheet({ person: this.myDetail, + /* 🔴🔴 必须传 embedded(2026-10-18 真机踩出来的真 bug): + `FbPersonSheet` 的根节点是"铺满全屏 + 内部居中"的浮层形态 + (它的设计宿主是"页面里叠遮罩 + Stack 居中",名册页就这么用)。 + 直接塞进 `bindSheet`(内容要自适应高度)会**测量互相打架**: + 真机症状是**每次点击 sheet 都创建了、紧接着 + `AceDrag: Drag gesture has been canceled` —— 起来立刻被关**, + 界面上看就是"点了没反应"(极易误判成"点击没接上")。 */ + embedded: true, onClose: (): void => { this.myDetailSheet = false; }, @@ -399,7 +410,10 @@ export struct FbTopBar { } } .width('100%') - .constraintSize({ maxHeight: '82%' }) + /* ⚠️ 不要给这层加 `constraintSize({maxHeight})`: + sheet 的高度由 `SheetSize.LARGE` 决定,卡片自己已有 `maxHeight:72%`; + 再叠一层百分比约束只会让"高度该多高"变成三方打架 + (真机症状就是浮层起来立刻被关)。 */ } /**