Skip to content

Fix: 안드로이드 그림자 적용 안됐던 문제 해결#20

Merged
alswlekk merged 1 commit intodevelopfrom
fix/push-sync-android-style-#12
Mar 18, 2026
Merged

Fix: 안드로이드 그림자 적용 안됐던 문제 해결#20
alswlekk merged 1 commit intodevelopfrom
fix/push-sync-android-style-#12

Conversation

@alswlekk
Copy link
Copy Markdown
Contributor

@alswlekk alswlekk commented Mar 18, 2026

🔗 관련 이슈

  • Close #

📙 작업 설명

📸 스크린샷 또는 시연 영상 (선택)

기능 미리보기 기능 미리보기
기능 설명 기능 설명

💬 추가 설명 or 리뷰 포인트 (선택)

Summary by CodeRabbit

릴리스 노트

  • Refactor
    • Android 플랫폼의 시각 효과 렌더링 방식을 개선했습니다. 그림자 표시 성능을 최적화하여 더욱 부드러운 UI 경험을 제공합니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 18, 2026

요약

Android 기반 그림자 효과 렌더링 구현을 per-layer 방식에서 drawWithCache 기반 네이티브 캔버스 렌더링으로 교체했습니다. 새로운 구현은 각 레이어에 대해 shadow layer를 설정하고 모서리가 둥근 사각형을 그린 후, 최종적으로 내용을 렌더링합니다.

변경 사항

코호트 / 파일 요약
Android 그림자 효과 렌더링
composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt
Per-layer folding shadow를 drawWithCache 기반 네이티브 캔버스 렌더링으로 변경. 라운드 레크트 그리기 및 shadow layer 설정 로직 추가, 불필요한 Modifier.shadow 제거. 관련 import 업데이트 (drawIntoCanvas, nativeCanvas 등).

예상 코드 리뷰 소요 시간

🎯 2 (Simple) | ⏱️ ~10 minutes

관련 가능성 있는 PR

추천 검토자

  • librawish808

시 🎨

그림자가 춤을 춘다네,

캔버스 위에 부드럽게,

레이어를 벗어나

더 빠르고 우아하게 ✨

네이티브 손길로 그려지는

안드로이드의 미학 🎭

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 사항의 주요 목표를 명확하게 설명하고 있습니다. Android 그림자 적용 문제 해결이라는 핵심 변경 사항을 잘 전달합니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/push-sync-android-style-#12
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.

OpenGrep is compatible with Semgrep configurations. Add an opengrep.yml or semgrep.yml configuration file to your project to enable OpenGrep analysis.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt (1)

43-56: 불필요한 drawRoundRect 호출 같아요.

clearShadowLayer() 호출 후 color = 0(완전 투명)인 paint로 drawRoundRect를 그리는데, 이건 화면에 아무것도 표시되지 않아서 제거해도 될 것 같아요. 혹시 의도된 동작이라면 주석으로 이유를 남겨주시면 좋겠어요.

💡 불필요한 코드 제거 제안
         }

         paint.clearShadowLayer()

-        drawIntoCanvas { canvas ->
-            val nc = canvas.nativeCanvas
-            nc.drawRoundRect(
-                0f,
-                0f,
-                size.width,
-                size.height,
-                radiusPx,
-                radiusPx,
-                paint,
-            )
-        }
-
         drawContent()
     }
 }
🤖 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 43 - 56, The drawn transparent rounded rect after
paint.clearShadowLayer() is redundant: remove the drawIntoCanvas block that
calls canvas.nativeCanvas.drawRoundRect(..., paint) when paint.color == 0 (fully
transparent), or if the draw is intentional, add a comment above
paint.clearShadowLayer()/drawIntoCanvas explaining the purpose; specifically
update the section using paint.clearShadowLayer(), drawIntoCanvas and
drawRoundRect to either delete the no-op draw call or document why it must
remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt`:
- Around line 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.

---

Nitpick comments:
In
`@composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt`:
- Around line 43-56: The drawn transparent rounded rect after
paint.clearShadowLayer() is redundant: remove the drawIntoCanvas block that
calls canvas.nativeCanvas.drawRoundRect(..., paint) when paint.color == 0 (fully
transparent), or if the draw is intentional, add a comment above
paint.clearShadowLayer()/drawIntoCanvas explaining the purpose; specifically
update the section using paint.clearShadowLayer(), drawIntoCanvas and
drawRoundRect to either delete the no-op draw call or document why it must
remain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3a0a013a-6461-4001-9bc3-697c14fb5fc3

📥 Commits

Reviewing files that changed from the base of the PR and between 6029907 and 8e6e595.

📒 Files selected for processing (1)
  • composeApp/src/androidMain/kotlin/com/konkuk/medicarecall/ui/theme/Effect.android.kt

Comment on lines +16 to +27
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(),
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.

@alswlekk alswlekk merged commit 0e52637 into develop Mar 18, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant