Compose-Lottie 애니메이션 동작 후, Intent로 Activity 전환하기
저는 평소에 Splash Activity를 별도로 Custom 하게 생성 후, Lottie 애니메이션을 포함시켜 구성하는 형태를 많이 사용했었습니다.
그러다 보니 Compose를 공부하면서 똑같은 형태를 구현해 보게 되었네요.
앱 실행 시 기본 네트워크 및 DB 처리가 완료되는 시간을 5초로 간주하고 Lottie 애니메이션이 그동안 동작하고 MainActivity로 넘어가는 구조를 설명하겠습니다.
먼저 Lottie 홈페이지에서 모션 이미지를 선택하여 JSON 형태의 데이터를 다운로드합니다.
이후, res - raw 폴더를 생성하여 해당 폴더에 다운로드한 Lottie 파일을 삽입합니다.
다음, Custom Splash Activity를 생성하여 시작 Activity로 지정합니다.
@SuppressLint("CustomSplashScreen")
class SplashActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MviComposeBasicTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
}
}
}
<activity
android:name=".SplashActivity"
android:exported="true"
android:theme="@style/Theme.MviComposeBasic">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Lottie를 앱 수준의 build.gradle에 Import 합니다.
https://airbnb.io/lottie/#/android-compose
implementation("com.airbnb.android:lottie-compose:6.0.1")
SplashActivity에 Lottie 애니메이션이 동작할 컴포저블 함수를 구현합니다.
@Composable
fun AnimatedPreLoader(modifier: Modifier = Modifier) {
//리소스 가져오기
val preLoaderLottieComposition by rememberLottieComposition(
LottieCompositionSpec.RawRes(
R.raw.testanim
)
)
val isPlayLottie = remember { mutableStateOf(true) }
//애니메이션 동작 설정
val preLoaderProgress = animateLottieCompositionAsState(
preLoaderLottieComposition,
iterations = LottieConstants.IterateForever,
isPlaying = isPlayLottie.value
)
val context = LocalContext.current
LaunchedEffect(key1 = true) {
delay(5000)
isPlayLottie.value = false
val intent = Intent(context, MainActivity::class.java)
context.startActivity(intent)
(context as? Activity)?.finish()
}
LottieAnimation(
composition = preLoaderLottieComposition,
progress = preLoaderProgress.value,
modifier = modifier
)
}
- preLoaderLottieComposition은 다운로드 받은 raw 폴더 하위의 Lottie 데이터를 가져오는 역할을 합니다.
- isPlayLottie라는 remember 변수를 생성하여 일정 시간 또는 작업이 마무리되면 애니메이션을 종료시킵니다.
//리소스 가져오기
val preLoaderLottieComposition by rememberLottieComposition(
LottieCompositionSpec.RawRes(
R.raw.testanim
)
)
val isPlayLottie = remember { mutableStateOf(true) }
preLoaderProgress에서는 Lottie 애니메이션 효과에 대한 각종 설정을 할 수 있습니다.
무한 반복 및 Play 상태에 대한 remember 변수 값 지정 정도 해주었습니다.
val preLoaderProgress = animateLottieCompositionAsState(
preLoaderLottieComposition,
iterations = LottieConstants.IterateForever,
isPlaying = isPlayLottie.value
)
.
.
.
@Composable
fun animateLottieCompositionAsState(
composition: LottieComposition?,
isPlaying: Boolean = true,
restartOnPlay: Boolean = true,
reverseOnRepeat: Boolean = false,
clipSpec: LottieClipSpec? = null,
speed: Float = 1f,
iterations: Int = 1,
cancellationBehavior: LottieCancellationBehavior = LottieCancellationBehavior.Immediately,
ignoreSystemAnimatorScale: Boolean = false,
useCompositionFrameRate: Boolean = false,
): LottieAnimationState {.....
비동기 동작 처리를 위한 LaunchedEffect를 활용하여 각종 데이터 및 api 처리, Lottie 애니메이션 종료, 화면 전환 등의 이벤트 처리를 해줍니다.
LaunchedEffect(key1 = true) {
delay(5000)
isPlayLottie.value = false
val intent = Intent(context, MainActivity::class.java)
context.startActivity(intent)
(context as? Activity)?.finish()
}
마지막으로 LottieAnimation 컴포넌트 선언을 통해 애니메이션을 표시합니다.
(LottieAnimation이 자꾸 deprecated 된 것으로 표시되는데, 해결 방법을 못 찾았네요; 혹시 알고 계시는 부분이 있다면 조언 부탁드리겠습니다!)
LottieAnimation(
composition = preLoaderLottieComposition,
progress = preLoaderProgress.value,
modifier = modifier
)
이제 onCreate 함수에서 적절한 사이즈와 범위를 Modifier로 지정하여 마무리합니다.
setContent {
MviComposeBasicTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Box {
AnimatedPreLoader(modifier = Modifier
.size(200.dp)
.align(Alignment.Center))
}
}
}
}
Lottie 애니메이션을 굳이 멈추거나 LaunchedEffect 활용 없이 onCreate에서 Coroutine을 사용해 바로 처리할 수도 있겠습니다.
@SuppressLint("CustomSplashScreen")
class SplashActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MviComposeBasicTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Box {
AnimatedPreLoader(modifier = Modifier
.size(200.dp)
.align(Alignment.Center))
}
}
}
}
lifecycleScope.launch(Dispatchers.Main) {
delay(5000) //초기 네트워크 및 DB 동작을 동기적으로 수행
val intent = Intent(this@SplashActivity, MainActivity::class.java)
startActivity(intent)
finish()
}
}
}