스플래시 화면

Android 12부터 SplashScreen API를 사용하면 실행 시 앱 내 모션, 앱 아이콘을 보여주는 스플래시 화면, 앱 자체로의 전환을 비롯한 애니메이션과 함께 앱을 실행할 수 있습니다. SplashScreenWindow이므로 Activity를 포함합니다.

그림 1. 스플래시 화면

스플래시 화면 환경은 앱을 시작할 때마다 표준 디자인 요소를 제공하지만 맞춤설정도 가능하므로 앱에서 고유한 브랜딩을 유지할 수 있습니다.

SplashScreen 플랫폼 API를 사용하는 것 외에도 SplashScreen API를 래핑하는 SplashScreen compat 라이브러리를 사용할 수도 있습니다.

스플래시 화면 작동 방식

앱 프로세스가 실행되지 않는 동안 (콜드 스타트) 사용자가 앱을 시작하거나 Activity가 생성되지 않은 경우 (웜 스타트) 다음 이벤트가 발생합니다.

  1. 시스템은 개발자가 정의한 테마와 애니메이션을 사용하여 스플래시 화면을 표시합니다.

  2. 앱이 준비되면 스플래시 화면이 닫히고 앱이 표시됩니다.

핫 스타트 중에는 스플래시 화면이 표시되지 않습니다.

스플래시 화면의 요소와 메커니즘

스플래시 화면의 요소는 Android 매니페스트 파일의 XML 리소스 파일에 의해 정의됩니다. 각 요소에는 밝은 모드와 어두운 모드 버전이 있습니다.

스플래시 화면의 맞춤설정 가능한 요소는 앱 아이콘, 아이콘 배경, 창 배경으로 구성됩니다.

스플래시 화면에 포함된 요소를 보여주는 이미지
그림 2. 맞춤설정 가능한 스플래시 화면 요소입니다.

그림 2에 표시된 다음 요소를 고려하세요.

1 앱 아이콘은 벡터 드로어블이어야 합니다. 정적 또는 애니메이션일 수 있습니다. 애니메이션의 지속 시간은 무제한일 수 있지만 1,000밀리초를 초과하지 않는 것이 좋습니다. 런처 아이콘이 기본값입니다.

2 아이콘 배경은 선택사항이며 아이콘과 창 배경 사이에 더 대비가 필요한 경우에 유용합니다. 적응형 아이콘을 사용하는 경우 창 배경과 충분히 대비되는 경우 배경이 표시됩니다.

3 적응형 아이콘과 마찬가지로 포그라운드의 1/3이 마스킹됩니다.

4 창 배경은 단일 불투명 색상으로 구성됩니다. 창 배경이 설정되어 있고 단색인 경우 속성이 설정되어 있지 않으면 기본적으로 사용됩니다.

스플래시 화면 크기

스플래시 화면 아이콘은 다음과 같이 적응형 아이콘과 동일한 사양을 사용합니다.

  • 브랜드 이미지: 200×80dp여야 합니다.
  • 아이콘 배경이 있는 앱 아이콘: 크기가 240×240dp여야 하며 지름 160dp의 원 안에 들어가야 합니다.
  • 아이콘 배경이 없는 앱 아이콘: 크기가 288×288dp여야 하며 지름 192dp의 원 안에 들어가야 합니다.

예를 들어 이미지의 전체 크기가 300×300dp인 경우 아이콘은 지름이 200dp인 원 안에 들어가야 합니다. 원 밖에 있는 모든 것이 보이지 않게 됩니다 (마스크).

단색 및 투명한 배경을 위해 다양한 아이콘 크기를 보여주는 이미지
그림 3. 단색 및 투명한 배경의 각각 스플래시 화면 아이콘 크기

스플래시 화면 애니메이션 및 실행 시퀀스

추가 지연 시간은 보통 콜드 스타트 시 앱을 실행하는 것과 관련이 있습니다. 스플래시 화면에 애니메이션 아이콘을 추가하면 미적 감각이 뛰어나고 더욱 프리미엄급 환경을 제공할 수 있습니다. 사용자 연구에 따르면 애니메이션을 볼 때 인지되는 시작 시간이 더 짧습니다.

스플래시 화면 애니메이션은 그림 4와 같이 실행 시퀀스 구성요소 내에 삽입됩니다.

런처 아이콘을 탭한 후 확대됨에 따라 화면이 채워지는 12개의 연속 프레임으로 실행 시퀀스를 보여주는 이미지
그림 4. 시퀀스를 실행합니다.
  1. 애니메이션 시작: 스플래시 화면의 시스템 뷰로 구성됩니다. 시스템에서 제어하며 맞춤설정할 수 없습니다.

  2. 스플래시 화면 (시퀀스의 '대기' 부분 동안 표시됨): 스플래시 화면을 맞춤설정할 수 있으므로 자체 로고 애니메이션과 브랜딩을 제공할 수 있습니다. 제대로 작동하려면 이 페이지에 설명된 요구사항을 충족해야 합니다.

  3. 종료 애니메이션: 스플래시 화면을 숨기는 애니메이션으로 구성됩니다. 맞춤설정하려면 SplashScreenView 및 아이콘을 사용하세요. 변환, 불투명도, 색상 설정을 사용하여 모든 애니메이션을 실행할 수 있습니다. 이 경우 애니메이션이 완료되면 수동으로 스플래시 화면을 삭제합니다.

아이콘 애니메이션을 실행할 때 앱이 더 일찍 준비된 경우 앱 시작 시 시퀀스를 건너뛸 수 있는 옵션이 제공됩니다. 앱이 onResume()를 트리거하거나 스플래시 화면이 자동으로 시간 초과되므로 모션을 편안하게 건너뛸 수 있는지 확인합니다. 스플래시 화면은 앱이 시각적 관점에서 안정적일 때만 onResume()를 사용하여 닫아야 하므로 추가 스피너가 필요하지 않습니다. 불완전한 인터페이스를 도입하면 사용자가 성가시게 할 수 있으며 예측이 불가능하거나 세련되지 않은 느낌을 줄 수 있습니다.

스플래시 화면 애니메이션 요구사항

스플래시 화면은 다음 사양을 준수해야 합니다.

  • 투명하지 않은 단일 창 배경 색상을 설정합니다. 주간 및 야간 모드는 SplashScreen compat 라이브러리에서 지원됩니다.

  • 애니메이션 아이콘이 다음 사양을 충족하는지 확인합니다.

    • 형식: 아이콘은 AnimatedVectorDrawable (AVD) XML이어야 합니다.
    • 크기: AVD 아이콘은 다음과 같이 적응형 아이콘의 4배 크기여야 합니다.
      • 아이콘 영역은 432dp여야 합니다. 즉, 마스킹되지 않은 적응형 아이콘의 108dp 영역의 4배입니다.
      • 이미지의 내부 3분의 2가 런처 아이콘에 표시되며 288dp여야 합니다. 즉, 적응형 아이콘의 내부 마스킹 영역을 구성하는 72dp의 4배입니다.
    • 지속 시간: 휴대전화에서 1,000ms를 초과하지 않는 것이 좋습니다. 지연된 시작을 사용할 수 있지만 166ms 이하여야 합니다. 앱 시작 시간이 1,000ms보다 길면 반복 애니메이션을 고려하세요.
  • 앱이 첫 프레임을 그릴 때 발생하는 스플래시 화면을 닫을 적절한 시간을 설정합니다. 스플래시 화면을 화면에 더 오래 표시하는 방법에 관한 섹션에 설명된 대로 이를 추가로 맞춤설정할 수 있습니다.

스플래시 화면 리소스

그림 5. AVD 예.

애니메이션을 만들고 형식을 지정한 후 AVD로 내보내는 방법을 보여주는 예제 스타터 키트를 다운로드합니다. 이 패키지에는 다음 도구가 포함되어 있습니다.

  • 애니메이션의 Adobe After Effects 프로젝트 파일입니다.
  • 마지막으로 내보낸 AVD XML 파일
  • 애니메이션의 GIF 예

이 파일을 다운로드하면 Google 서비스 약관에 동의하는 것으로 간주됩니다.

Google 개인정보처리방침에 이 서비스의 데이터 처리 방식이 설명되어 있습니다.

앱의 스플래시 화면 맞춤설정

기본적으로 windowBackground가 단일 색상인 경우 SplashScreen는 테마의 windowBackground를 사용합니다. 스플래시 화면을 맞춤설정하려면 앱 테마에 속성을 추가합니다.

다음 중 한 가지 방법으로 앱의 스플래시 화면을 맞춤설정할 수 있습니다.

  • 테마 속성을 설정하여 모양을 변경합니다.

  • 화면에 더 오래 표시합니다.

  • 스플래시 화면 닫기 애니메이션을 맞춤설정합니다.

시작하기

핵심 SplashScreen 라이브러리는 API 23부터 모든 기기에 Android 12 스플래시 화면을 제공합니다. 프로젝트에 추가하려면 다음 스니펫을 build.gradle 파일에 추가합니다.

Groovy

dependencies {
    implementation "androidx.core:core-splashscreen:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.core:core-splashscreen:1.0.0")
}

스플래시 화면 테마를 설정하여 모양 변경

Activity 테마에서 다음 속성을 지정하여 앱의 스플래시 화면을 맞춤설정할 수 있습니다. android:windowBackground과 같은 속성을 사용하는 기존 스플래시 화면 구현이 이미 있다면 Android 12 이상의 대체 리소스 파일을 제공하는 것이 좋습니다.

  1. windowSplashScreenBackground를 사용하여 배경을 특정 단색으로 채웁니다.

    <item name="android:windowSplashScreenBackground">@color/...</item>
    
  2. windowSplashScreenAnimatedIcon을 사용하여 시작 창의 중앙에 있는 아이콘을 바꿉니다.

    Android 12 (API 수준 32)만 타겟팅하는 앱의 경우 다음을 실행합니다.

    객체가 AnimationDrawableAnimatedVectorDrawable를 통해 애니메이션 가능하고 드로어블인 경우 시작 창을 표시하는 동안 애니메이션을 재생하도록 windowSplashScreenAnimationDuration를 설정합니다. Android 13에서는 기간이 AnimatedVectorDrawable에서 직접 추론되므로 이 작업이 필요하지 않습니다.

    <item name="android:windowSplashScreenAnimatedIcon">@drawable/...</item>
    
  3. windowSplashScreenAnimationDuration를 사용하여 스플래시 화면 아이콘 애니메이션의 지속 시간을 나타냅니다. 이를 설정해도 스플래시 화면이 표시되는 실제 시간에는 영향을 미치지 않지만 SplashScreenView.getIconAnimationDuration를 사용하여 스플래시 화면 종료 애니메이션을 맞춤설정할 때 가져올 수 있습니다. 자세한 내용은 스플래시 화면을 화면에 더 오래 표시하는 방법을 참고하세요.

    <item name="android:windowSplashScreenAnimationDuration">1000</item>
    
  4. windowSplashScreenIconBackgroundColor를 사용하여 스플래시 화면 아이콘 뒤의 배경을 설정합니다. 이 기능은 창 배경과 아이콘 간의 대비가 충분하지 않은 경우에 유용합니다.

    <item name="android:windowSplashScreenIconBackgroundColor">@color/...</item>
    
  5. windowSplashScreenBrandingImage를 사용하여 스플래시 화면 하단에 표시할 이미지를 설정할 수 있습니다. 그러나 디자인 가이드라인에서는 브랜드 이미지 사용을 권장하지 않습니다.

    <item name="android:windowSplashScreenBrandingImage">@drawable/...</item>
    
  6. windowSplashScreenBehavior를 사용하여 Android 13 이상에서 앱이 항상 스플래시 화면에 아이콘을 표시할지 지정할 수 있습니다. 기본값은 0입니다. 이 값은 시작 활동이 splashScreenStyleSPLASH_SCREEN_STYLE_ICON로 설정하면 스플래시 화면에 아이콘을 표시하고, 실행 활동이 스타일을 지정하지 않으면 시스템 동작을 따릅니다. 빈 스플래시 화면을 표시하지 않고 항상 애니메이션 아이콘을 표시하려면 icon_preferred 값으로 설정합니다.

    <item name="android:windowSplashScreenBehavior">icon_preferred</item>
    

스플래시 화면을 화면에 더 오래 표시

스플래시 화면은 앱이 첫 프레임을 그리는 즉시 닫힙니다. 로컬 디스크에서 인앱 설정을 비동기식으로 로드하는 등 소량의 데이터를 로드해야 한다면 ViewTreeObserver.OnPreDrawListener를 사용하여 첫 번째 프레임을 그리도록 앱을 정지할 수 있습니다.

그리기 전에 시작 활동이 완료되면(예: 콘텐츠 뷰를 설정하지 않고 onResume 전에 종료) 사전 그리기 리스너가 필요하지 않습니다.

Kotlin

// Create a new event for the activity.
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Set the layout for the content view.
    setContentView(R.layout.main_activity)

    // Set up an OnPreDrawListener to the root view.
    val content: View = findViewById(android.R.id.content)
    content.viewTreeObserver.addOnPreDrawListener(
        object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                // Check whether the initial data is ready.
                return if (viewModel.isReady) {
                    // The content is ready. Start drawing.
                    content.viewTreeObserver.removeOnPreDrawListener(this)
                    true
                } else {
                    // The content isn't ready. Suspend.
                    false
                }
            }
        }
    )
}

Java

// Create a new event for the activity.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Set the layout for the content view.
    setContentView(R.layout.main_activity);

    // Set up an OnPreDrawListener to the root view.
    final View content = findViewById(android.R.id.content);
    content.getViewTreeObserver().addOnPreDrawListener(
            new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    // Check whether the initial data is ready.
                    if (mViewModel.isReady()) {
                        // The content is ready. Start drawing.
                        content.getViewTreeObserver().removeOnPreDrawListener(this);
                        return true;
                    } else {
                        // The content isn't ready. Suspend.
                        return false;
                    }
                }
            });
}

스플래시 화면 닫기 애니메이션 맞춤설정

Activity.getSplashScreen()을 통해 스플래시 화면의 애니메이션을 추가로 맞춤설정할 수 있습니다.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // ...

    // Add a callback that's called when the splash screen is animating to the
    // app content.
    splashScreen.setOnExitAnimationListener { splashScreenView ->
        // Create your custom animation.
        val slideUp = ObjectAnimator.ofFloat(
            splashScreenView,
            View.TRANSLATION_Y,
            0f,
            -splashScreenView.height.toFloat()
        )
        slideUp.interpolator = AnticipateInterpolator()
        slideUp.duration = 200L

        // Call SplashScreenView.remove at the end of your custom animation.
        slideUp.doOnEnd { splashScreenView.remove() }

        // Run your animation.
        slideUp.start()
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...

    // Add a callback that's called when the splash screen is animating to the
    // app content.
    getSplashScreen().setOnExitAnimationListener(splashScreenView -> {
        final ObjectAnimator slideUp = ObjectAnimator.ofFloat(
                splashScreenView,
                View.TRANSLATION_Y,
                0f,
                -splashScreenView.getHeight()
        );
        slideUp.setInterpolator(new AnticipateInterpolator());
        slideUp.setDuration(200L);

        // Call SplashScreenView.remove at the end of your custom animation.
        slideUp.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                splashScreenView.remove();
            }
        });

        // Run your animation.
        slideUp.start();
    });
}

이 콜백이 시작되면 스플래시 화면의 애니메이션 벡터 드로어블이 시작됩니다. 앱 실행 시간에 따라 드로어블이 애니메이션 중간에 있을 수 있습니다. SplashScreenView.getIconAnimationStart를 사용하여 애니메이션이 시작된 시점을 알 수 있습니다. 다음과 같이 아이콘 애니메이션의 남은 시간을 계산할 수 있습니다.

Kotlin

// Get the duration of the animated vector drawable.
val animationDuration = splashScreenView.iconAnimationDuration
// Get the start time of the animation.
val animationStart = splashScreenView.iconAnimationStart
// Calculate the remaining duration of the animation.
val remainingDuration = if (animationDuration != null && animationStart != null) {
    (animationDuration - Duration.between(animationStart, Instant.now()))
        .toMillis()
        .coerceAtLeast(0L)
} else {
    0L
}

Java

// Get the duration of the animated vector drawable.
Duration animationDuration = splashScreenView.getIconAnimationDuration();
// Get the start time of the animation.
Instant animationStart = splashScreenView.getIconAnimationStart();
// Calculate the remaining duration of the animation.
long remainingDuration;
if (animationDuration != null && animationStart != null) {
    remainingDuration = animationDuration.minus(
            Duration.between(animationStart, Instant.now())
    ).toMillis();
    remainingDuration = Math.max(remainingDuration, 0L);
} else {
    remainingDuration = 0L;
}

추가 리소스