SuperAPI AI 工具集

self-hiding-child-cannot-hide-its-slot

编程与开发

查看项目

更新于 10-17 16:17

技能介绍

用途

该条目属于 Kotlin UI(Compose)工程实践类陷阱说明,针对「可选控件不渲染自身,却无法隐藏他人为其添加的外层容器」这一问题,给出契约声明、调用方门控方式与代码审计验证手段。

主要主张

  1. 契约随组件声明:在声明组件的同一文件中导出可用性判定(如 expect fun isOptionalControlAvailable(): Boolean),并在注释中明确「为控件提供独立容器的布局在判定为 false 时也必须隐藏容器」。
  2. 不要在各调用点重复推导:若多个调用点自行根据平台检查推导「是否可用」,最终会不一致,而不一致的一方恰好会画出空盒。统一由一个与组件共用同一平台代码的导出判定函数负责。
  3. 门控只在该加时加:仅当调用方为控件增加了容器时才需要门控;直接裸调用时控件自身为空是不可见的。文中示例中同一控件在分段组里被 if (available) 包裹、在普通行里裸调用,两者都正确,因此「每个调用点都必须门控」的审计结论是错的。
  4. 分段组的形状按位置分配:端帽、圆角、分隔线由位置决定;删掉中间槽位算术仍成立,删掉首尾槽位则端帽需移动,否则组外侧出现两个直角。应从构建出的列表推导形状,而非按索引硬编码。
  5. 无点击槽位需要真实分支:可点击与不可点击的容器是不同的 composable,语义不同。传入 onClick = {} 会保留涟漪、无障碍点击动作并继续消费点击,导致内部自有点击的控件收不到事件。应依据 onClick != null 分支,在 else 中输出普通容器。
  6. 判定与组件作为一对平台声明同文件:把控件桩为不渲染的目标,必须在同一次修改中把判定桩为 false;分文件维护会漂移,且直到构建该目标才暴露。
  7. 判定须轻量且纯:它在组合期、每次重组、布局循环内被调用,常量返回的平台函数可以;任何 I/O、读 store、访问服务都应提升为状态向下传,否则组会卡顿。
  8. 区分消失与保留空间:加权行中移除槽位会把宽度重新分配给兄弟控件,导致其余控件尺寸变化。永久不可用通常应移除,瞬态不可用应保留占位,否则组会反复跳动。
  9. 「不渲染就不占成本」不成立:带 weight(1f) 或背景的空容器仍会占据行份额并绘制容器颜色。

验证方式

文中给出以下审计命令:

确认判定函数存在且声明在组件旁:

grep -rn --include='*.kt' --exclude-dir=build "expect fun is[A-Za-z]*Available(): Boolean" .

列出组件调用点及其上方门控,人工确认未门控的调用点确实没有添加容器:

F=$(grep -rl --include='*.kt' --exclude-dir=build "expect fun is[A-Za-z]*Available(): Boolean" .)
C=$(grep -oE "^expect fun [A-Za-z]+" "$F" | awk '{print $3}' | head -1)
grep -rn --include='*.kt' --exclude-dir=build -B8 "^ *$C(" . | grep -E "$C\(|Available\(\)"

确认槽位使用真实分支而非空点击:

grep -rn --include='*.kt' --exclude-dir=build -A6 "onClick: (() -> Unit)?" .

在特性不可用的设备或目标上打开界面并清点组内单元格:多出一个、间隙变宽或外侧直角,都说明槽位存活得比控件更久。

适用场景与限制

适用于 Kotlin/Compose 多平台 UI 中带可选控件、分段组、加权布局的实现与代码审查。条目为工程经验说明,未提供产品化工具、安装方式或收费信息;命令为审计脚本示例,需在实际仓库环境中运行,具体行为依仓库结构而定。