SuperAPI AI 工具集

ambient-tone-layer-behind-flat-pages

前端与建站

查看项目

更新于 10-17 16:16

技能介绍

用途

图片背景的页面靠图片获得个性,而设置、通知等扁平页面则什么都没有,看起来像另一个应用。这个共享层解决了这个问题:一个从色调到页面颜色的倾斜双色渐变,高度固定。

主要能力

  • 提供 AmbientThemeGlow 可组合函数,接受 modifier 和可空的 tint 颜色参数。
  • 根据主题明暗对色调进行混合:浅色主题下向白色提亮(粉彩感),深色主题下加深(rgbFactor(0.45f))。
  • 使用 animateColorAsState 对色调变化做 500 毫秒动画,避免硬切换闪烁。
  • 在底部叠加一个 180dp 高的遮罩,使渐变尾部平滑过渡,不产生硬边。
  • 高度定义为共享常量 AmbientGlowHeight = 360.dp。

使用方式

在屏幕主体的第一条语句调用,放在列表之前,无需包裹容器:

AmbientThemeGlow(tint = rememberGlowTint(currentRecord?.imageUrl))
LazyColumn(state = listState, …) { … }

滚动移出通过 graphicsLayer 在绘制阶段读取偏移实现:

AmbientThemeGlow(tint = …, modifier = Modifier.graphicsLayer {
    translationY =
        if (listState.firstVisibleItemIndex == 0) -listState.firstVisibleItemScrollOffset.toFloat()
        else -size.height
})

适用场景

  • 需要与图片背景页面保持视觉一致性的扁平页面(设置、通知等)。
  • 页面顶部需要随内容滚动而移出的环境色调层。

限制与注意事项

  • 不要用自定义 Box 包裹屏幕:导航目标内容已组合进堆叠容器,包裹会改变子项约束,导致滚动容器测量异常。
  • tint 为 null 时必须让渐变塌缩为页面颜色(不可见),不能替换为主题色,否则空闲应用会为未播放的记录发光。
  • Color.Unspecified 是“尚未解析”的哨兵值,不是真实颜色,否则首帧会闪现错误色调。
  • 尾部颜色必须指向页面实际绘制的背景色,而非 colorScheme.background,否则在带面板颜色的外壳上会出现硬接缝。
  • 混合系数应属于色调来源,而非层本身;共享层用 0.45 加深,而屏幕自带的图片色调用 0.30。
  • 第一个列表项必须高于该层,否则交接时会跳变。
  • 顶部应用栏默认容器颜色会遮住唯一带颜色的部分,应设为透明,让栏对光晕做毛玻璃处理。
  • 高度是共享常量,手写副本应导入该常量而非硬编码 360。
  • 需要更多功能的屏幕应保留自己的副本:共享层只接受一个色调;自行从数据动画色调、或需要位于自身模糊源内的屏幕保留手写副本。

验证方法

# 1. 查找所有使用该层及导入高度常量的位置
grep -rn --include='*.kt' -e 'AmbientThemeGlow(' -e 'AmbientGlowHeight' . | grep -v '/build/'

# 2. 检查绘制阶段滚动移出
grep -rn -A4 --include='*.kt' 'graphicsLayer {' . | grep -v '/build/' | grep 'firstVisibleItemScrollOffset'

# 3. 检查 null 塌缩分支
grep -rn -A4 --include='*.kt' 'tint == null ->' . | grep -v '/build/'

# 4. 验证堆叠声明
JAR=$(find ~/.gradle/caches/modules-2 -name 'navigation-compose*.jar' | sort -V | tail -1) && echo "$JAR"
D=$(mktemp -d) && unzip -oq "$JAR" -d "$D" && javap -p -classpath "$D" androidx.navigation.compose.NavHostKt | grep -c 'ui\.Alignment'

目视检查:未选中任何内容时,页面应与删除该层后无法区分;选中强图片后滚动到底部再返回,观察第一个列表项离开视口时的跳变。