[Android Compose] TopBar 배경색 전환 애니메이션 구현 방법

2025. 2. 5. 15:31·Android/Compose

안녕하세요! Android 개발자 한민재 입니다. 오늘은 SOPT에서 진행한 합동세미나중, Jetpack Compose로 TopBar에 스크롤 애니메이션을 적용해보면서 알게 된 내용들을 공유하려 해요.

💡 구현 목표

  • 스크롤 전에는 투명 배경의 TopBar예요
  • 스크롤 후에는 흰색 배경으로 자연스럽게 전환돼요
  • 배경색 변화에 따라 아이콘 색상이 자동으로 대응해요

🛠 구현 방법

비교적 과거에 작성한 코드니 부족한 부분은 눈감아 주세요ㅠ

1. 스크롤 상태 감지하기

val scrollState = rememberLazyListState()
val isScrolledPastImage = scrollState.firstVisibleItemIndex > 0 ||
    scrollState.firstVisibleItemScrollOffset > 0

LazyColumn의 스크롤 상태를 확인해서 이미지 영역을 지났는지 체크해요.

2. 배경색 애니메이션 적용하기

val backgroundColor by animateColorAsState(
    targetValue = if (isScrolledPastImage) Color.White else Color.White.copy(alpha = 0f),
    animationSpec = tween(durationMillis = 800),
    label = "배경색 애니메이션"
)

3. TopBar 컴포넌트 만들기

@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 내용
    }
}

 

🚀 적용된 모습

⚠️ 구현하면서 만난 이슈들

1. z-index 관련 문제

Scaffold 안에서 TopBar와 content 영역이 있을 때, TopBar가 위에 겹쳐 보여야 했는데 잘 되지 않았어요. Scaffold의 구조상 TopBar와 content가 따로 구분되어 있어서 생긴 문제예요.

// TopBar는 위에 보이도록 zIndex를 설정해요
modifier = Modifier.zIndex(1f)
// 콘텐츠는 아래에 보이도록 설정해요
LazyColumn(
    modifier = Modifier.zIndex(0f)
)

2. 아이콘 색상 처리하기

배경이 투명에서 흰색으로 바뀔 때 아이콘이 안 보이는 구간이 생기지 않도록, 배경색의 밝기를 기준으로 아이콘 색상을 정했어요.

val iconTint = if (backgroundColor.luminance() < 0.5f) Color.White else Color.Black

🔍 animateColorAsState 옵션 살펴보기

기본 파라미터

  • targetValue: 최종 색상 값이에요
  • animationSpec: 애니메이션 동작 방식이에요
  • label: 디버깅용 레이블이에요
  • finishedListener: 애니메이션 끝났을 때 실행될 동작이에요

animationSpec 종류

  1. tween - 시간 기준 애니메이션이에요
tween(
    durationMillis = 800,
    easing = FastOutSlowInEasing
)
  1. spring - 물리 기반 애니메이션이에요
spring(
    dampingRatio = Spring.DampingRatioMediumBouncy,
    stiffness = Spring.StiffnessMedium
)
  1. keyframes - 구간별 애니메이션이에요
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
}

💫 더 개선할 수 있는 부분들

1. alpha 값 활용하기

val backgroundAlpha = if (isScrolledPastImage) 1f else 0f
val backgroundColor by animateColorAsState(
    targetValue = Color.White.copy(alpha = backgroundAlpha)
)

2. Palette API 활용하기

배경 이미지의 색상을 가져와서 더 자연스러운 색상 전환을 만들 수 있어요.

val palette = Palette.from(bitmap).generate()
val dominantColor = palette.getDominantColor(Color.White)

 

그렇다면 이미지 영역을 벗어났을때는 어떻게 해야할까요? 이건 추후에 구현하겠습니다..

참고사항

  • Jetpack Compose 버전은 1.0.0 이상
  • 최소 SDK 버전은 Android 5.0 (API level 21) 이상

'Android > Compose' 카테고리의 다른 글

[Android Compose] Effect Handlers 딥다이브  (2) 2025.06.20
[Android Compose] 상태 읽기 지연(Defer State Reads)으로 리컴포지션 최적화하기  (0) 2025.06.18
[Android Compose] Figma의 타원형 Radial Gradient를 구현해보자  (0) 2025.06.06
[Android Compose] Figma 그림자를 쉽게 만들어 보자  (1) 2025.05.14
[Android Compose] ImePadding 이중 패딩 문제 해결 방법 (+키보드 영역 조정)  (6) 2025.02.05
'Android/Compose' 카테고리의 다른 글
  • [Android Compose] 상태 읽기 지연(Defer State Reads)으로 리컴포지션 최적화하기
  • [Android Compose] Figma의 타원형 Radial Gradient를 구현해보자
  • [Android Compose] Figma 그림자를 쉽게 만들어 보자
  • [Android Compose] ImePadding 이중 패딩 문제 해결 방법 (+키보드 영역 조정)
한민돌
한민돌
Android 개발자가 되기까지.
  • 한민돌
    미래 가젯 연구소
    한민돌
  • 전체
    오늘
    어제
    • 분류 전체보기 (13)
      • Android (1)
        • Compose (8)
        • Jetpack (2)
      • Kotlin (2)
        • Kotlin In Action (0)
      • 외부 활동 (0)
        • SOPT (0)
        • SOPT makers (0)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

    • GitHub
  • 인기 글

  • 태그

    runcatching
    LaunchedEffect
    imagedecoder
    Google Recommend Architecture
    onfailure
    coroutune
    Android
    effecthandler
    coroutine
    jetpack
    build-logic
    derivedstateof
    compose
    Multi-module
    lazyverticalgrid
    sideeffect
    producestate
    custom plugin
    rememberupdatedstate
    imagecompress
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
한민돌
[Android Compose] TopBar 배경색 전환 애니메이션 구현 방법
상단으로

티스토리툴바