-
Notifications
You must be signed in to change notification settings - Fork 0
Fix: 안드로이드 그림자 적용 안됐던 문제 해결 #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
61 changes: 51 additions & 10 deletions
61
composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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(), | ||
| ) | ||
| 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() | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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