/** * 家书 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 }) } }