[Android] Compose Navigation에서 화면 전환 시 흰색 깜빡임 문제

이주형·2025년 4월 8일

❗ 문제 상황

화면이 전환될 때마다 흰색이 잠깐 번쩍이는 현상이 발생했습니다. 위와 같이 "장소 선택" 화면에서 "소리 선택" 화면으로 넘어갈 때, 아주 짧은 순간이지만 흰색 배경이 깜빡이며 부드럽지 않은 전환을 만들었습니다. 이는 사용자 경험을 해칠 뿐만 아니라, 제가 원했던 매끄러운 앱 흐름과 거리가 멀었습니다. 이 문제를 반드시 고쳐야겠다고 생각했습니다.!

❓ 원인 파악

화면 전환 중에 NavHost가 새 화면을 그리기 전에 기본 배경색이 노출되는 게 아닐까 하는 생각이 들었습니다. 이 가설을 Navigation의 원리와 연관지어 좀 더 깊이 파고들어 보았습니다.
Navigation Compose에서 NavHost는 화면 전환을 관리하는 컨테이너 역할을 합니다. 사용자가 새로운 경로(route)로 이동하면, NavHost는 현재 Composable을 제거하고 새 Composable을 렌더링합니다. 이 과정은 즉각적이어야 하지만, 실제로는 약간의 시간 차이가 발생할 수 있습니다. 특히, 새 화면의 Composable이 준비되기 전에 NavHost의 기본 배경이 노출될 수 있습니다.
안드로이드에서 기본 배경은 일반적으로 흰색(#FFFFFF)으로 설정되어 있습니다. 만약 앱 테마나 NavHost에 명시적인 배경색이 지정되지 않았다면, 전환 중에 이 기본 배경이 잠깐 드러날 가능성이 높습니다. Navigation의 내부 동작을 보면, NavHost는 NavController의 상태 변화를 감지해 화면을 교체하는데, 이 과정에서 이전 화면이 사라지고 새 화면이 그려지기까지의 짧은 공백이 생길 수 있습니다. 이 공백 동안 NavHost의 배경이 없으면 시스템 레벨의 배경(흰색)이 노출되는 것입니다.
제 앱의 경우, 테마에서 배경색을 설정했더라도 NavHost 자체에 배경이 명시되지 않아 이런 현상이 발생했다고 추측했습니다. 이게 맞는지 확인하기 위해 배경 설정을 점검하기로 했습니다.

✅ 해결 방법

원인을 배경 색상 문제로 좁힌 뒤, 해결책을 찾아보았습니다. 핵심은 화면 전환 중 빈틈없이 배경색을 일관되게 유지하는 것이었습니다. 제가 사용한 코드를 단계별로 설명하겠습니다.

우선 저는 앱 전체를 다크 모드을 기준으로 작업했습니다.

@Composable
fun PomoSoundTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColorScheme
        else -> LightColorScheme
    }

    MaterialTheme(
        colorScheme = DarkColorScheme, // 다크모드만 적용되도록
        typography = Typography,
        content = content
    )
}

그리고 각 Screen의 background를 MaterialTheme.colorScheme.background를 사용하고 있었습니다.

NavHost를 감싸는 PomoSoundNavHost컴포넌트를 Surface자체에 배경색을 적용했습니다. 이렇게 하면 화면 전환 시 기본 배경이 노출될 틈이 없어집니다.

// 기존 코드
@Composable
fun PomoSoundApp() {
    val navController = rememberNavController()
    PomoSoundNavHost(
        navController = navController
    )
}

// 변경한 코드
@Composable
fun PomoSoundApp() {
    val navController = rememberNavController()
    Surface(
        modifier = Modifier.fillMaxSize(),
        color = MaterialTheme.colorScheme.background
    ) {
        PomoSoundNavHost(
            navController = navController
        )
    }
}

🎈 결과

이 코드를 적용한 뒤 앱을 실행해 보았더니, 드디어 흰색 깜빡임이 사라졌습니다! 화면 전환이 훨씬 부드럽게 느껴졌고, 제가 원했던 매끄러운 사용자 경험이 완성되었습니다. 문제는 NavHost가 새 화면을 렌더링하기 전에 기본 배경(흰색)이 잠깐 노출됐던 것이었고, 이를 테마와 UI 레벨에서 일관된 배경색으로 덮어줌으로써 해결된 것이었습니다.

0개의 댓글