안녕하세요! 이번에 Jetpack Compose로 TopBar 구현을 하면서 스크롤에 따른 배경색 애니메이션을 적용해보았는데, 그 과정에서 알게 된 내용들을 공유해보려 합니다.
val scrollState = rememberLazyListState()
val isScrolledPastImage = scrollState.firstVisibleItemIndex > 0 ||
scrollState.firstVisibleItemScrollOffset > 0
LazyColumn의 스크롤 상태를 체크해서 이미지 영역을 지나쳤는지 확인합니다.
val backgroundColor by animateColorAsState(
targetValue = if (isScrolledPastImage) Color.White else Color.White.copy(alpha = 0f),
animationSpec = tween(durationMillis = 800),
label = "배경색 애니메이션"
)
@Composable
fun ProductTopBar(
onBackClick: () -> Unit,
onHomeClick: () -> Unit,
backgroundColor: Color,
modifier: Modifier = Modifier
) {
val iconTint = if (backgroundColor.luminance() < 0.5f) Color.White else Color.Black
Row(
modifier = modifier
.zIndex(1f)
.fillMaxWidth()
.background(backgroundColor)
.padding(top = 45.dp, start = 16.dp, end = 16.dp, bottom = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
// TopBar 내용
}
}
Scaffold 내부에서 TopBar와 content 영역이 있을 때, TopBar가 content 위에 겹쳐서 표시되어야 했는데 제대로 동작하지 않았습니다. Scaffold의 구조상 TopBar와 content가 별도의 slot으로 구분되어 있어 발생한 문제였습니다.
// TopBar는 상위에 위치하도록 zIndex 설정
modifier = Modifier.zIndex(1f)
// 콘텐츠는 하위에 위치하도록 설정
LazyColumn(
modifier = Modifier.zIndex(0f)
)
배경색이 투명에서 흰색으로 변할 때 아이콘이 보이지 않는 구간이 생기는 것을 방지하기 위해, 배경색의 명도를 기준으로 아이콘 색상을 결정했습니다.
// luminance를 기준으로 아이콘 색상 결정
val iconTint = if (backgroundColor.luminance() < 0.5f) Color.White else Color.Black
tween(
durationMillis = 800,
easing = FastOutSlowInEasing
)
spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessMedium
)
keyframes {
durationMillis = 1000
Color.White.copy(alpha = 0f) at 0
Color.White.copy(alpha = 0.5f) at 500
Color.White.copy(alpha = 1f) at 1000
}
val backgroundAlpha = if (isScrolledPastImage) 1f else 0f
val backgroundColor by animateColorAsState(
targetValue = Color.White.copy(alpha = backgroundAlpha)
)
배경 이미지의 색상을 추출하여 더 조화로운 색상 전환을 구현할 수 있습니다.
하지만 설정한 영역이 이미지를 벗어났을 경우는? →도전!
val palette = Palette.from(bitmap).generate()
val dominantColor = palette.getDominantColor(Color.White)