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>
그중에서 위 속성을 적용해 주면 스플래시의 아이콘을 변경해 줄 수 있다.
댓글