Android/Splash

[Android] SplashScreen 사용하기

O_Gyong 2023. 4. 16.

Android 12부터 스플래시 화면을 구현하기 위한 SplashScreen API(참고)가 추가되면서 모든 앱이 시작할 때 스플래시 화면에 앱 아이콘을 보여주게 되었다. 이것 때문에 SplashScreen의 처리를 하지 않으면 앱 아이콘이 포함된 스플래시 화면이 먼저 노출되었다가 사용자가 구현한 스플래시 화면이 보이는 이슈가 생겼다.

앱 아이콘이 스플래시로 보임

 

기존에는 스플래시 화면을 구현하기 위해서 직접 화면을 만들어야 했다. 하지만 SplashScreen이 등장하고 나서는 직접 화면을 만들 필요도 없고 애니메이션과 같은 효과와 더불어 스플래시 화면을 간단하게 만들 수 있게 되었다.

 

그럼 기존 방식에 문제가 있었는가 하면 앱의 시작 상태 중 Hot Start에 그 이유가 있다. Hot Start 상태에서는 앱이 실행될 때 메모리에 저장된 자원을 다시 가져오는데 기존 방식처럼 직접 구현한 경우 해당 자원이 다시 로드되면서 자원 소모와 로딩에 시간이 걸리게 된다.

 

이런 문제를 해결하기 위해서 SplashScreen이 도입되었다.


SplashScreen 의존성 추가

// SlashScreen
implementation 'androidx.core:core-splashscreen:1.0.0'

 


스플래시 화면 시간 조절

SplashScreen의 스플래시 화면은 첫 프레임을 그리는 즉시 닫힌다. 이것을 조절하려면 ViewTreeObserver.OnPreDrawListener를 사용하면 된다. (참고)

class MainActivity : AppCompatActivity() {

    private val mViewModel: MainViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.addOnPreDrawListener(
            object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    return if (!mViewModel.isLoading.value) {
                        content.viewTreeObserver.removeOnPreDrawListener(this)
                        true
                    } else {
                        false
                    }
                }
            }
        )
    }
}

해당 코드는 안드로이드에서 뷰 트리를 그리려고 할 때 호출되는 콜백 메서드로, 실제로 뷰가 표시되기 전에 속성을 변경할 수 있다. onPreDraw에서 boolean 값을 반환하는데, true이면 이후 레이아웃 처리를 계속하고 false이면 레이아웃 처리를 중지한다.

 

class MainViewModel: ViewModel() {
    private var _isLoading = MutableStateFlow(true)
    val isLoading = _isLoading

    init {
        viewModelScope.launch {
            delay(1500L)
            _isLoading.value = false
        }
    }
}

onPreDraw에서 Boolean 값을 반환하기 전에 임의로 ViewModel에서 1.5초를 딜레이 시켰다. 실제로 사용한다면 delay를 주지 않고 작업이 마무리될 때를 기준으로 잡으면 될 것 같다.

 

그리고 onPreDrawListener를 ViewTreeObserver에서 제거하기 위해 removeOnPreDrawListener를 호출한다.


애니메이션 적용하기

Activity.getSplashScreen을 사용하면 스플래시 화면이 닫힐 때 애니메이션을 설정해 줄 수 있다.

override fun onCreate(savedInstanceState: Bundle?) {
    
    ...
    
    splashScreen.setOnExitAnimationListener { splashScreenView ->
        ObjectAnimator.ofFloat(
            splashScreenView,
            View.TRANSLATION_Y,
            0f,
            -splashScreenView.height.toFloat()
        ).run {
            interpolator = AnticipateInterpolator()
            duration = 1000
            doOnEnd { splashScreenView.remove() }
            start()
        }
    }
}

ObjectAnimator를 이용하여 애니메이션을 정의할 수 있다.- 목표 타겟(View)- 애니메이션 동작 방식 설정(위 코드에서는 수직 방향으로)- 시작 위치- 종료 위치

 

정의를 하고 AnticipateInterpolator()를 이용하여 밀려나는 느낌을 주고, 애니메이션이 1초로 동작하도록, 마지막으로 SplashScreen을 remove 해준다. 


스플래시 이미지 변경

Theme 속성을 지정하면 스플래시에 다양한 설정을 할 수 있다.

<item name="android:windowSplashScreenAnimatedIcon">@drawable/...</item>

그중에서 위 속성을 적용해 주면 스플래시의 아이콘을 변경해 줄 수 있다.

 

전체 코드

댓글