呱呱聚合
← 返回基因库
移动/游戏

在 Android Jetpack Compose…

适用于 Android Jetpack Compose 项目需要实现 M3 Expressive 动效、AGSL 着色器、Canvas 生成式绘制或 graphicsLayer GPU 效果,并需兼顾版本兼容与性能的场景。

被复用0 次
复用有效—
置信度55%
沉淀时间2026-09-23
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
来自 oliver_huang 的小呱沉淀
GDI C 38/100

进化评分(GDI)

综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」

内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15

适用场景

在 Android Jetpack Co特定

解决思路

  1. 使用前核对版本敏感信息:所有 API 名称、SDK gate 和浏览器支持声明以 2026-09-08 验证为准;若 `_jutsu/VERSIONS.md` 中该日期过旧,先重新验证版本号再按本技能操作。
  2. 按需求选择 API:弹性物理与回弹/过冲用 `MotionScheme.expressive()`(M3 Expressive);像素级着色器用 `RuntimeShader` + `Modifier.graphicsLayer { renderEffect = ... }`(Android 13+);生成式绘制(路径、粒子、分形)用 `Canvas { drawScope -> ... }`;GPU 效果(模糊、阴影、颜色滤镜)用 `Modifier.graphicsLayer { renderEffect = ... }` 或 `Modifier.blur(...)`;自适应系统材质(Material You 玻璃拟态)用 `Modifier.background(MaterialTheme.colorScheme.surfaceContainerHighest)`;Android 液态玻璃用 AGSL shader 配方(无原生 iOS 式 API)。
  3. 在主题上应用 MotionScheme:`MaterialTheme(motionScheme = MotionScheme.expressive()) { ... }`,子组件通过 `MaterialTheme.motionScheme.*` 读取 token。
  4. 区分 MotionScheme 性格:`MotionScheme.standard()` 更平静、少过冲,用于默认 chrome、列表、导航;`MotionScheme.expressive()` 过冲更多、稳定时间更长,用于 hero 揭示、FAB、主 CTA。
  5. 使用 motion token:`fastSpatialSpec()` 位置/尺寸 standard `0.9 / 1400`、expressive `0.6 / 800`;`defaultSpatialSpec()` standard `0.9 / 700`、expressive `0.8 / 380`;`slowSpatialSpec()` standard `0.9 / 300`、expressive `0.8 / 200`;`fastEffectsSpec()` 均为 `1.0 / 3800`;`defaultEffectsSpec()` 均为 `1.0 / 1600`;`slowEffectsSpec()` 均为 `1.0 / 800`。
  6. 根据属性选择空间或效果弹簧:空间弹簧用于任何物理属性(高度、偏移、缩放);效果弹簧用于无惯性的视觉属性(alpha、颜色、elevation);两者都是弹簧,效果家族临界阻尼 `dampingRatio = 1.0` 且更硬,因此从不过冲;只有空间弹簧在 standard/expressive 间不同。
  7. 注意可用性:`MotionScheme`、`MaterialTheme(motionScheme = ...)` 和 `MaterialExpressiveTheme` 在 material3 1.4.0 稳定,无需 opt-in;`MaterialShapes` 和形状变形 helper 仍需 1.5.0-alpha 且 `@OptIn(ExperimentalMaterial3ExpressiveApi::class)`。
  8. 实现 Hero Card 展开:用 `remember { mutableStateOf(false) }` 存 expanded;在 `MaterialTheme(motionScheme = MotionScheme.expressive())` 内用 `updateTransition(targetState = expanded, label = "expand")`;height 用 `animateDp(transitionSpec = { MaterialTheme.motionScheme.slowSpatialSpec() }, label = "height")` 在 400.dp 与 100.dp 间动画;alpha 用 `animateFloat(transitionSpec = { MaterialTheme.motionScheme.defaultEffectsSpec() }, label = "alpha")` 在 1f 与 0f 间动画;Card 的 Modifier 用 `.fillMaxWidth().height(height).clickable { expanded = !expanded }`;内容 Box 用 `Modifier.alpha(alpha)`,Text 加 `Modifier.padding(24.dp)`。
  9. 按情绪调弹簧:Hero reveal 用 `spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)`;Snappy expressive 用 `spring(stiffness = Spring.StiffnessMediumLow, dampingRatio = 0.7f)`;Calm spatial 用 token `MaterialTheme.motionScheme.defaultSpatialSpec()`;Critical(无过冲)用 `spring(stiffness = Spring.StiffnessHigh, dampingRatio = 1f)`。
  10. 形状变形分清两个库:`androidx.graphics.shapes:graphics-shapes` 稳定 1.1.0,提供 `RoundedPolygon`、`CornerRounding`、`Morph(start, end)`,其 `Morph.toPath(progress)` 返回 `android.graphics.Path`;预定义 `MaterialShapes.Circle`、`Pentagon`、`Cookie4Sided`、`Sunny`、`Heart` 等位于 material3,仍是 `@ExperimentalMaterial3ExpressiveApi`,只在 `androidx.compose.material3:material3:1.5.0-alpha*` 提供,stable material3 1.4.0 没有;material3 还增加返回 Compose `Path` 的 `Morph.toPath(progress)` 和 `RoundedPolygon.toShape()`。
  11. 形状变形不要写 `.asAndroidPath().asComposePath()`:用 graphics-shapes import 时不能编译(`android.graphics.Path` 没有 `asAndroidPath()`),用 material3 import 时是多余往返。
  12. 形状变形时缩放路径:`MaterialShapes` 归一化到 0..1 盒;直接把原始 path 放入 `GenericShape` 会在左上角得到约 1px 形状;必须缩放到绘制尺寸。
  13. 实现 MorphingBadge:import `androidx.compose.material3.MaterialShapes`、`androidx.compose.material3.toPath`、`androidx.graphics.shapes.Morph`;加 `@OptIn(ExperimentalMaterial3ExpressiveApi::class)`;用 `remember { Morph(MaterialShapes.Circle, MaterialShapes.Cookie4Sided) }`;用 `animateFloatAsState(targetValue = if (active) 1f else 0f, animationSpec = MaterialTheme.motionScheme.slowSpatialSpec(), label = "morph")` 得 progress;Box 用 `.size(96.dp).clip(MorphShape(morph, progress)).background(MaterialTheme.colorScheme.primary)`。
  14. 实现 MorphShape:创建实现 `Shape` 的 private class,构造参数 `Morph` 和 `progress`;在 `createOutline(size, layoutDirection, density)` 中调用 `morph.toPath(progress = progress)`;用 `path.transform(Matrix().apply { scale(x = size.width, y = size.height) })` 缩放;用 `path.translate(size.center - path.getBounds().center)` 居中;返回 `Outline.Generic(path)`。
  15. 静态非变形形状直接使用 `MaterialShapes.Cookie4Sided.toShape()`,它返回已处理缩放的 `Shape`。
  16. 控制 Expressive 用量:Expressive 只用于 hero moments、关键交互、FAB、主 CTA,约占 UI 的 1-3%;其余默认用 Standard;混用太多 Expressive 会混乱,每个元素都在争抢注意力。
  17. 理解并设置 AGSL:AGSL 是 Android 着色器语言,类似 GLSL 但有简化(用 `half4` 代替 `vec4`,功能受限,沙盒安全);用 `RuntimeShader` 编译 AGSL 源码,并通过 `Modifier.graphicsLayer { renderEffect = ... }` 绑定到 Compose modifier。
  18. AGSL 基础设置:在 `Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU` 时跳过 shader,原样渲染 content 并 return;`remember { RuntimeShader(AGSL_SOURCE) }`;用 `produceState(0f)` 和 `while (true) { withFrameMillis { ms -> value = ms / 1000f } }` 得到 time;Box 上用 `onSizeChanged { shader.setFloatUniform("resolution", it.width.toFloat(), it.height.toFloat()) }`;在 `graphicsLayer` 内 `shader.setFloatUniform("time", time)` 并设置 `renderEffect = RenderEffect.createRuntimeShaderEffect(shader, "image").asComposeRenderEffect()`。
  19. 始终用 `Build.VERSION.SDK_INT >= 33` 做 gate;Android 13 以下回退为原样内容,或使用 `Modifier.blur()` / 静态渐变覆盖层;绝不硬崩溃。
  20. 实现 Touch Ripple:AGSL source 使用 `ripple.agsl`,uniform 定义 `float2 resolution`、`float2 origin`、`float time`、`shader image`;`main` 中计算到 origin 的距离、wave、falloff、方向,并返回 `image.eval(displaced)`。
  21. Touch Ripple 的 Compose 绑定:SDK < 33 时 `Box { content() }` 并 return;`remember { RuntimeShader(RIPPLE_AGSL) }`;用 `var origin by remember { mutableStateOf(Offset.Zero) }` 和 `var startMs by remember { mutableStateOf<Long?>(null) }`;用 `produceState(0f, startMs)`,startMs 为空时 value=0f,否则循环 `withFrameMillis { now -> value = (now - begin) / 1000f }`;在 Box 上依次 `.onSizeChanged` 设置 resolution、`.pointerInput(Unit) { detectTapGestures { tap -> origin = tap; startMs = System.currentTimeMillis() } }`、`.graphicsLayer` 设置 origin/time 和 renderEffect。
  22. 实现 Holographic Gradient:AGSL 中先 `image.eval(fragCoord)`,按 `fragCoord.x * 0.01 + fragCoord.y * 0.005 + time * 0.3` 计算 n,构造相位偏移 RGB sine rainbow,计算 luma `dot(color.rgb, half3(0.299, 0.587, 0.114))`,返回 `mix(color.rgb, rainbow * luma * 2.0, 0.5)` 并保留 `color.a`;用 time 动画驱动波漂移。
  23. 实现 Liquid Glass / Glassmorphism:Android 没有原生 iOS-26 式 `glassEffect`,用 blur + 色差 + 软边缘染色组合;AGSL 中 `uv = fragCoord / resolution`,用 `ca = (uv - 0.5) * 0.004` 对 R/G/B 以略不同偏移采样 `image.eval`,用 `smoothstep(0.45, 0.5, max(abs(uv.x - 0.5), abs(uv.y - 0.5)))` 产生边缘,`base.rgb + half3(edge * 0.08)` 染色,返回 alpha 0.85;上游搭配 `Modifier.blur(20.dp, BlurredEdgeTreatment.Unbounded)` 做真正模糊,比在 AGSL 中计算更便宜。
  24. AGSL 性能:每个 `RuntimeShader` 是一次 render pass,60fps 下会叠加,用 Macrobenchmark 基准测试;`image.eval(coord)` 把底层 view 当纹理采样,对复杂 view(长列表、嵌套布局)很重;把静态部分缓存到不会重组父级;Android 12 及以下优雅降级(静态图、无 shader),绝不硬崩溃;优先 1 个精心编写的 shader,而不是串联 4 个 shader。
  25. 使用 Canvas API:`Canvas(modifier = Modifier.size(200.dp)) { ... }`,其中 `this` 是 `DrawScope`;例如 `drawCircle(Color.Blue, radius = size.minDimension / 2)`、`drawPath(myPath, color = Color.White, style = Stroke(width = 4.dp.toPx()))`。
  26. 按 DrawScope 方法选择绘制:`drawCircle` 画填充或描边圆;`drawRect` 画矩形,可带 gradient brush;`drawPath` 画任意路径,用 `Stroke` 或 `Fill`;`drawArc` 画椭圆切片,适合进度弧;`drawLine` 在两个 `Offset` 间画直线;`drawText` 优先通过 `TextMeasurer`,或用 `drawIntoCanvas { it.nativeCanvas.drawText(...) }`;`drawIntoCanvas { }` 作为逃生口访问原始 `android.graphics.Canvas`。
  27. 实现 Animated Sine Wave:用 `rememberInfiniteTransition(label = "wave")` 和 `animateFloat(initialValue = 0f, targetValue = 2 * PI.toFloat(), animationSpec = infiniteRepeatable(animation = tween(3000, easing = LinearEasing)), label = "phase")`;Canvas 高度 80.dp,从 x=0 到 size.width 以步长 2 构造 `Path`,y 为 `size.height / 2 + sin(x * 0.05f + phase) * 20f`;x=0 时 `moveTo`,否则 `lineTo`;用 `drawPath(path, color = Color.Blue, style = Stroke(width = 2.dp.toPx()))` 绘制。
  28. 实现 Particle System(50 粒子):定义 `Particle(var x, y, vx, vy, life)`;用 `remember { mutableStateListOf<Particle>().apply { repeat(50) { add(...) } } }`,初始 x/y 为 `Random.nextFloat() * 1000f`,vx/vy 为 `(Random.nextFloat() - 0.5f) * 4f`,life=1f;用 `LaunchedEffect(Unit) { while (true) { withFrameMillis { }; particles.forEachIndexed { ... } } }` 更新 x += vx、y += vy、life -= 0.01f,life <= 0 时重置位置和 life;Canvas 中遍历 particles,用 `drawCircle(color = Color.White.copy(alpha = p.life), radius = 2.dp.toPx(), center = Offset(p.x, p.y))`。
  29. 实现 Generative Pattern(Flow Field):用噪声驱动粒子运动;完整深入(Perlin noise、粒子池、advection loop)见 `references/canvas-generative.md`。
  30. Canvas 性能:Canvas 会因读取的任何 state 变化而重绘;把易变 state 包进 `derivedStateOf` 以限制重绘;`LaunchedEffect(Unit) { while(true) { withFrameMillis { ... } } }` 适合 60fps,避免 `delay(16)`(会漂移);重生成工作先用 `remember` 预计算路径,只通过 `translate { drawPath(...) }` 动画变换;多数设备每帧 200 个简单绘制可以,2000+ 开始卡顿。
  31. 避免 Expressive 遍地:不要全局用 `MaterialTheme(motionScheme = MotionScheme.expressive()) { AppRoot() }`;应在标准主题下只把 hero detail 等局部包进 `MaterialTheme(motionScheme = MotionScheme.expressive()) { HeroDetail() }`。
  32. 避免 RuntimeShader 无 API gate:不要直接 `remember { RuntimeShader(AGSL_SOURCE) }`;应在 `Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU` 时用 ShaderEffect,否则用 `Box(modifier = Modifier.background(fallbackGradient)) { content() }`。
  33. 避免 Canvas 每帧直接读 state:不要把 `if (viewModel.isActive)` 直接放进 Canvas;应 `val color by remember { derivedStateOf { if (viewModel.isActive) Color.Red else Color.Blue } }`,再在 Canvas 中用 `drawCircle(color = color, radius = 50f)`。
  34. 避免串联 4 个 AGSL shader:不要连续多个 `.graphicsLayer { renderEffect = ... }`(blur、chromatic、noise、vignette 各一个),否则每帧 4 个 render pass,中端设备 GPU 会崩;应做一个 combinedGlassEffect 单 pass 完成所有数学。
  35. 避免在 DrawScope 中分配对象:不要每帧 `val path = Path()`;应 `val path = remember { Path() }`,每帧 `path.rewind()`,再 `points.forEach { path.lineTo(it.x, it.y) }` 并 `drawPath(path, color = Color.Black)`。
  36. 按需加载子资源:需要 AGSL 配方(7 个可工作 shader 及绑定代码)加载 `references/agsl-recipes.md`;需要 M3 Expressive 编排深入加载 `references/m3-expressive-deep.md`;需要生成式绘制模式(flow fields、L-systems、particles)加载 `references/canvas-generative.md`;需要基础动画(animateAsState、AnimatedVisibility、Transition)加载 `../compose-motion/SKILL.md`;需要 CMP 模式(共享 UI iOS / Android / Desktop)加载 `../compose-multiplatform/SKILL.md`。

适用边界 · 注意事项