SuperAPI AI 工具集

angled-gradient-modifier

前端与建站

查看项目

更新于 10-17 16:16

技能介绍

用途

该技能解决 Compose 中「按任意角度绘制线性渐变」的问题。Brush.linearGradient 接收的是两个端点坐标而非角度,因此「30° 的渐变」实际要回答的是:两个端点应放在哪里,才能让渐变恰好以 30° 横跨整个盒子。答案取决于盒子的宽高比,所以同一个 brush 无法在组合(composition)阶段一次性构建,必须放在绘制修饰符内,此时尺寸已知。

主要能力

提供 Modifier.angledGradientBackground(colors: List<Color>, degrees: Float) 扩展。其逻辑为:

  • 取盒子尺寸 (x, y),计算 gamma = atan2(y, x),即盒子自身对角线的角度,它是「射线从垂直边离开」与「从水平边离开」的分界。
  • 将角度归一化到 [0, 360),再转为弧度 alpha。
  • 按 alpha 所在区间计算 gradientLength:落在垂直边区间时为 x / cos(alpha),水平边区间时为 y / sin(alpha),其余象限用对应的负值形式,兜底为 hypot(x, y)。
  • 由 gradientLength 得到 offsetX、offsetY,以盒子中心为基准构造 Brush.linearGradient 的 start/end,并用 drawRect 绘制。

公式要点:γ = atan2(h, w) 是中心射线穿过盒子角点的角度。垂直边情形下长度为 w / |cos α|,因此水平半偏移恰为 w/2,端点按构造落在边上;另一坐标 (w/2)·tan α 由区间判断保证不超过 h/2。

使用方式

将 angledGradientBackground 作为 Modifier 链的一环使用,传入颜色列表与角度(度)。资料强调:不要在其下方再设置 background(...) 颜色,因为 drawBehind 每次绘制都会重绘,第二层不透明背景属于不可见的无用功。

适用场景

当设计需要非轴对齐角度的渐变,或该角度需要动画时,应使用此角度计算方案。轴对齐方向(左→右、上→下)无需这套计算,可直接用无限端点坐标让 Brush.linearGradient 代入盒子尺寸。

限制与陷阱

  • 旋转对角线会超出边界,截断到边缘会扭曲角度:用长度 hypot(w, h)/2 的向量旋转,仅四个角点正确;其他位置中心到边界的距离更小,端点会落到盒子外,只显示渐变中段,永远到不了两端颜色。把超出的点裁剪回最近边缘虽能修正超出,却会横向移动该点,使两端连线不再是指定角度。
  • 比较前必须归一化角度:Kotlin 的 % 保留被除数符号,-30f % 360 仍为 -30f,会穿过所有区间判断落入兜底分支。余数为负时需加 360。
  • 退化盒子产生零长度渐变而非除零:γ 会塌缩为 0(零高)或 π/2(零宽),此时所选分支的分子正是塌缩的维度,长度算出来为 0,两端点都落在中心。真正的 0/0 需要除数也恰好为零,而由 Float 的 π 构造出的这些角度不会出现该情况。仍应对 γ 提前退出:此时什么都画不出来,且盒子在获得尺寸前确实会被测量为零。
  • 保留不可达的 else:四个区间在数学上覆盖 [0, 2π],但用浮点比较且边界为闭区间,γ 是 Float 而由 π 推导的边界是 Double。去掉 else 会导致编译失败(作为表达式的 when 必须穷尽),而对角线是兜底的合理答案。
  • 屏幕角度为顺时针,因为 y 向下增长:0° 从左到右,45° 从左上到右下,90° 从上到下。从逆时针测量的设计工具移植角度时需取负,而上述归一化陷阱正是使其安全的前提。
  • 应拦截 colors.size < 2:单色是调用方错误(只有一端的「渐变」),拦截成本仅一次比较。
  • 轴对齐方向无需这套计算:Brush.linearGradient 会用盒子尺寸替换无限端点坐标。在 ui-graphics-android 1.12.0-alpha03 中,其 createShader 会对四个坐标与 Float.POSITIVE_INFINITY 比较并替换为 size.width / size.height。注意 Offset.Infinite 在两个坐标上都是无限,端点会落在远角,渐变沿 atan2(h, w) 即盒子对角线方向,只有正方形时才是 45°。

验证方法

  • 查找所有调用点并核对角度常量是否符合上述顺时针约定:grep -rn --include='*.kt' "angledGradientBackground(" . | grep -v '/build/'
  • 查找应改用该修饰符的手写端点计算(start/end 为计算值而非 Offset.Zero/Offset.Infinite):grep -rn -A6 --include='*.kt' "Brush.linearGradient(" . | grep -v '/build/' | grep -E "start =|end ="
  • 用两个差异最大的颜色(纯红到纯蓝、无 alpha)验证两端点确实落在边缘:盒子角落应能看到两种纯色;端点超出的渐变只会显示浑浊的紫色。
  • 在渐变显示时把盒子从正方形改为很宽再改回,可见角度必须不变——这正是逐象限分支的意义,也是固定端点渐变会出错的地方。

其他说明

资料中给出的代码为「改编版(已裁剪守卫子句)」,并提示被移除的守卫见 Traps 部分。分类方面,该技能属于 Compose UI 绘制与图形处理,资料未提供更多平台、收费或价格信息。