Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,60 @@
package com.konkuk.medicarecall.ui.theme

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.Dp

actual fun Modifier.figmaShadow(
group: ShadowGroup,
cornerRadius: Dp,
): Modifier = group.layers.fold(this) { acc, layer ->
acc.shadow(
elevation = layer.blurRadius,
shape = RoundedCornerShape(cornerRadius),
ambientColor = layer.color,
spotColor = layer.color,
clip = false
)
): Modifier = this.drawWithCache {
val radiusPx = cornerRadius.toPx()
val paint = Paint().asFrameworkPaint().apply {
isAntiAlias = true
color = 0
}

onDrawWithContent {
group.layers.forEach { layer ->
paint.setShadowLayer(
layer.blurRadius.toPx(),
layer.offsetX.toPx(),
layer.offsetY.toPx(),
layer.color.toArgb(),
Comment on lines +16 to +27
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Android setShadowLayer hardware acceleration Compose drawWithCache

💡 Result:

In traditional Android Views, Paint.setShadowLayer for non-text elements (e.g., shapes, paths) is not supported with hardware acceleration enabled (default since API 14). It requires setting the view to software rendering via view.setLayerType(View.LAYER_TYPE_SOFTWARE, null), which can impact performance. Jetpack Compose is hardware accelerated by default. Official docs recommend using built-in shadow APIs like Modifier.shadow(elevation), Modifier.dropShadow(Shadow), or Modifier.innerShadow for shadows, which handle hardware acceleration properly without needing setShadowLayer. However, custom shadow implementations in Compose often use drawBehind or drawWithCache with drawIntoCanvas { paint.asFrameworkPaint.setShadowLayer(...) } to access native Paint.setShadowLayer. This inherits the same limitation: setShadowLayer does not work reliably with hardware acceleration for non-text. - On API 28+ (Pie), some effects like BlurMaskFilter work with HW accel, but setShadowLayer for shapes remains unsupported (per official HW accel docs). - Pre-API 28, effects fail entirely. - Workarounds: Disable HW accel (not recommended, poor perf), use offscreen bitmaps/Pictures rendered in software, multi-layer gradients, or BlurMaskFilter (limited support). Example custom shadow using drawWithCache (from sources, but subject to HW limitations): kotlin fun Modifier.shadowWithClippingShadowLayer( elevation: Dp, shape: Shape = CircleShape, spotColor: Color = Color.Black.copy(alpha = 0.25f) ): Modifier = this.drawWithCache { if (elevation > 0.dp) { val blurRadiusPx = elevation.toPx val dxPx = 0f val dyPx = (elevation * 0.5f).toPx val outline = shape.createOutline(size, layoutDirection, this) val path = Path.apply { addOutline(outline) } val shadowPaint = Paint.apply { asFrameworkPaint.apply { isAntiAlias = false setShadowLayer(blurRadiusPx, dxPx, dyPx, spotColor.toArgb) } } onDrawWithContent { clipPath(path, ClipOp.Difference) { drawIntoCanvas { canvas -> canvas.drawPath(path, shadowPaint) } } drawContent } } else { onDrawWithContent { drawContent } } } Prefer official APIs for compatibility and performance. Use custom setShadowLayer only if necessary, testing across API levels, and consider alternatives like gradients for full HW support.

Citations:


setShadowLayer()는 Compose의 하드웨어 가속 환경에서 제대로 동작하지 않아요.

Android 공식 문서에서 명시하고 있듯이, setShadowLayer()는 도형이나 경로 같은 텍스트가 아닌 요소에 대해서는 하드웨어 가속 활성 상태에서 지원되지 않습니다. Compose가 기본으로 하드웨어 가속을 사용하기 때문에, 실제 기기에서 그림자가 제대로 보이지 않을 가능성이 높습니다.

Modifier.shadow()Modifier.dropShadow() 같은 공식 API를 사용하는 걸 추천하거나, 꼭 필요하면 오프스크린 비트맵 기법을 고려해 봐도 좋아요. graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)을 적용해서 해당 레이어만 소프트웨어 렌더링으로 처리하는 방법도 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt`
around lines 16 - 27, The use of Paint.setShadowLayer(...) inside
onDrawWithContent (where paint is created via Paint().asFrameworkPaint()) will
not reliably render under Compose's hardware-accelerated pipeline; replace this
shadow approach by either applying a Compose shadow API (e.g., Modifier.shadow
or Modifier.dropShadow) to the composable that draws group.layers, or force
software/offscreen compositing for just that drawing region by wrapping the
drawing with graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
before calling onDrawWithContent and removing the setShadowLayer call on paint;
update references to paint.setShadowLayer(...) and ensure layer
blur/offset/color values from group.layers are mapped to the chosen Modifier or
the offscreen rendering path.

)
drawIntoCanvas { canvas ->
val nc = canvas.nativeCanvas
nc.drawRoundRect(
0f,
0f,
size.width,
size.height,
radiusPx,
radiusPx,
paint,
)
}
}

paint.clearShadowLayer()

drawIntoCanvas { canvas ->
val nc = canvas.nativeCanvas
nc.drawRoundRect(
0f,
0f,
size.width,
size.height,
radiusPx,
radiusPx,
paint,
)
}

drawContent()
}
}
Loading