Summary
The issue of a red outline or background leaking around a swipable card in Jetpack Compose occurs when two composables are layered on top of each other. The bottom composable is a red delete background using matchParentSize(), and the top composable is a swipable Card. Both composables use the same RoundedCornerShape(8.dp), but the red background is still visible outside the card bounds.
Root Cause
The root cause of this issue is due to the following reasons:
- The
Boxcomposable with the red background is not being clipped correctly. - The
Cardcomposable is being elevated, causing it to be drawn on top of the background, but not covering the entire area. - The
RoundedCornerShapeis not being applied correctly to the background, causing it to leak outside the card bounds.
Why This Happens in Real Systems
This issue can occur in real systems when:
- Using layered composables with different shapes and elevations.
- Not applying clipping correctly to the background composable.
- Not considering the elevation and shape of the foreground composable.
Real-World Impact
The real-world impact of this issue is:
- A visually unappealing UI with a red outline around the card.
- A poor user experience due to the unexpected visual behavior.
- Difficulty in debugging the issue due to the complex interaction between composables.
Example or Code
val maxOffset = with(LocalDensity.current) { 80.dp.toPx() }
var offsetX by remember { mutableStateOf(0f) }
Box {
Box(
Modifier
.matchParentSize()
.clip(RoundedCornerShape(8.dp))
.background(Color.Red)
.clickable { /* handle click */ },
contentAlignment = Alignment.CenterEnd
) {
// content
}
Card(
modifier = Modifier
.fillMaxWidth()
.offset { IntOffset(offsetX.roundToInt(), 0) }
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta -> offsetX = (offsetX + delta).coerceIn(-maxOffset, 0f) },
onDragStopped = { /* handle drag stop */ }
),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.onTertiary),
elevation = CardDefaults.cardElevation(defaultElevation = 3.dp),
shape = RoundedCornerShape(8.dp),
) {
// content
}
}
How Senior Engineers Fix It
Senior engineers fix this issue by:
- Applying correct clipping to the background composable using
Modifier.clip(). - Considering the elevation and shape of the foreground composable.
- Using debugging tools to visualize the composables and identify the issue.
Why Juniors Miss It
Juniors may miss this issue due to:
- Lack of understanding of composable layout and clipping.
- Insufficient experience with Jetpack Compose and its nuances.
- Not thoroughly testing the UI for different scenarios and edge cases.