📌

Jetpack Compose入門 アプリを作る知識-3(画面遷移アニメーション~navigation-animation)

2022/03/29に公開

概要

Jetpack Composeで画面遷移の際にアニメーションをしたい場合にどうやるかという話です。
残念ながら、2022/03/28の段階では、いまだに安定版がリリースされていなくて、試験運用版APIとして提供されています。
なので、正式版の場合は実装方法が全然変わっている可能性があります。

実装方法

前回の実装の画面遷移をアニメーションさせようと思います。

ライブラリを追加します。

+ implementation "com.google.accompanist:accompanist-navigation-animation:0.24.5-alpha"

Kotlinの実装は、画面遷移の実装が分かっていれば、非常に簡単です。(単純な画面遷移は以前の記事を参照ください)
アニメーション無しの実装とほぼ変わりません。
変更箇所は、以下の箇所だけです。

  • rememberNavController
    -> rememberAnimatedNavController
  • NavHost
    -> AnimatedNavHost
  • import androidx.navigation.compose.composable
    -> import com.google.accompanist.navigation.animation.composable
・・・
-import androidx.navigation.compose.composable
+import com.google.accompanist.navigation.animation.composable
・・・
-  val navController = rememberNavController()
-  NavHost(navController = navController, startDestination = "main") {
+  val navController = rememberAnimatedNavController()
+  AnimatedNavHost(navController = navController, startDestination = "main") {

また、試験運用版APIなので、

@ExperimentalAnimationApi or @OptIn(ExperimentalAnimationApi::class)を利用している関数に記述する必要があります。

@OptIn(ExperimentalAnimationApi::class)
@Composable
fun MyContentView() {

結果、こんなフェードイン、フェードアウトなアニメーションになります。(このgifは再生時間スケールをx10に設定しています)

これは、AnimatedNavHost()関数を見るとわかりますが、enterTransitionexitTransitionでfadeInを指定しているからです。

@Composable
@ExperimentalAnimationApi
public fun AnimatedNavHost(
    navController: NavHostController,
    startDestination: String,
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.Center,
    route: String? = null,
    enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
        { fadeIn(animationSpec = tween(700)) },
    exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
        { fadeOut(animationSpec = tween(700)) },
    popEnterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) = enterTransition,
    popExitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) = exitTransition,
    builder: NavGraphBuilder.() -> Unit
)

なので、この引数を変えれば色々とアニメーションを変更できます。
たとえば、iOS風に横スライド遷移も可能です。

  val navController = rememberAnimatedNavController()
  AnimatedNavHost(navController = navController, startDestination = "main",
    enterTransition = {
      slideIn { fullSize -> IntOffset(fullSize.width, 0) }
    },
    popEnterTransition = {
      slideIn { fullSize -> IntOffset(-fullSize.width, 0) }
    },
    exitTransition = {
      slideOut { fullSize -> IntOffset(-fullSize.width, 0) }
    },
    popExitTransition = {
      slideOut { fullSize -> IntOffset(fullSize.width, 0) }
    },
    ) {
    composable("main") {
      ListTitles(contents = mocks) { index ->
        navController.navigate("second/$index")
      }
    }
    composable(
      "second/{index}",
      arguments = listOf(navArgument("index") { type = NavType.IntType })
    ) { backStackEntry ->
      Detail(backStackEntry.arguments?.getInt("index") ?: 1) {
        navController.navigateUp()
      }
    }
  }

NewsPicks の Zenn

Discussion