0

我已经在我的项目中实现了伴奏导航动画库,并且偶然发现了两个问题。第一个问题是从一个屏幕导航到另一个屏幕时没有应用动画。第二个问题是系统的“返回”将应用程序关闭到后台而不是返回到上一个屏幕。

这是从 MainActivity 开始的应用程序布局。

MainActivity.kt

@ExperimentalAnimationApi
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val preDrawListener = ViewTreeObserver.OnPreDrawListener { false }

    override fun onCreate(savedInstanceState: Bundle?) {
        setTheme(R.style.MyHomeTheme)
        super.onCreate(savedInstanceState)

        WindowCompat.setDecorFitsSystemWindows(window, false)

        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.addOnPreDrawListener(preDrawListener)

        lifecycleScope.launch {
            setContent {
                val systemUiController = rememberSystemUiController()

                SideEffect {
                    systemUiController.setStatusBarColor(
                        color = Color.Transparent,
                        darkIcons = true
                    )
                    systemUiController.setNavigationBarColor(
                        color = Color(0x40000000),
                        darkIcons = false
                    )
                }
                MyHomeApp(
                    currentRoute = Destinations.Welcome.WELCOME_ROUTE
                )
            }
            unblockDrawing()
        }
    }

    private fun unblockDrawing() {
        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.removeOnPreDrawListener(preDrawListener)
        content.viewTreeObserver.addOnPreDrawListener { true }
    }
}

MyHomeApp.kt

@ExperimentalAnimationApi
@Composable
fun MyHomeApp(currentRoute: String) {
    MyHomeTheme {
        ProvideWindowInsets {
            val navController = rememberAnimatedNavController()
            val scaffoldState = rememberScaffoldState()
            val darkTheme = isSystemInDarkTheme()

            val items = listOf(
                HomeTab.Dashboard,
                HomeTab.Details,
                HomeTab.Settings
            )

            val navBackStackEntry by navController.currentBackStackEntryAsState()
            val currentDestination = navBackStackEntry?.destination

            val bottomPaddingModifier = if (currentDestination?.route?.contains("welcome") == true) {
                Modifier
            } else {
                Modifier.navigationBarsPadding()
            }

            Scaffold(
                modifier = Modifier
                    .fillMaxSize()
                    .then(bottomPaddingModifier),
                scaffoldState = scaffoldState,
                bottomBar = {
                    if (currentDestination?.route in items.map { it.route }) {
                        BottomNavigation {
                            items.forEach { screen ->
                                BottomNavigationItem(
                                    label = { Text(screen.title) },
                                    icon = {},
                                    selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
                                    onClick = {
                                        navController.navigate(screen.route) {
                                            // Pop up to the start destination of the graph to
                                            // avoid building up a large stack of destinations
                                            // on the back stack as users select items
                                            popUpTo(navController.graph.findStartDestination().id) {
                                                saveState = true
                                            }
                                            // Avoid multiple copies of the same destination when
                                            // reselecting the same item
                                            launchSingleTop = true
                                            // Restore state when reselecting a previously selected item
                                            restoreState = true
                                        }
                                    }
                                )
                            }
                        }
                    }
                }
            ) { innerPadding ->
                MyHomeNavGraph(
                    modifier = Modifier.padding(innerPadding),
                    navController = navController,
                    startDestination = navBackStackEntry?.destination?.route ?: currentRoute
                )
            }
        }
    }
}

sealed class HomeTab(
    val route: String,
    val title: String
) {
    object Dashboard : HomeTab(
        route = Destinations.Home.HOME_DASHBOARD,
        title = "Dashboard"
    )

    object Details : HomeTab(
        route = Destinations.Home.HOME_DETAILS,
        title = "Details"
    )

    object Settings : HomeTab(
        route = Destinations.Home.HOME_SETTINGS,
        title = "Settings"
    )
}

MyHomeNavGraph.kt

@ExperimentalAnimationApi
@Composable
fun MyHomeNavGraph(
    modifier: Modifier = Modifier,
    navController: NavHostController,
    startDestination: String
) {
     val actions = remember(navController) { Actions(navController = navController) }

    AnimatedNavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable(
            route = Destinations.Welcome.WELCOME_ROUTE,
            enterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            exitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            popEnterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            },
            popExitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            }
        ) {
            WelcomeScreen(
                navigateToLogin = actions.navigateToWelcomeLogin,
                navigateToRegister = actions.navigateToWelcomeRegister,
            )
        }
        composable(
            route = Destinations.Welcome.WELCOME_LOGIN_ROUTE,
            enterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            exitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            popEnterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            },
            popExitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            }
        ) {
            WelcomeLoginScreen(
                // Arguments will be passed to navigate to the home screen or other
            )
        }
    }
}

class Actions(val navController: NavHostController) {
    // Welcome
    val navigateToWelcome = {
        navController.navigate(Destinations.Welcome.WELCOME_ROUTE)
    }
    val navigateToWelcomeLogin = {
        navController.navigate(Destinations.Welcome.WELCOME_LOGIN_ROUTE)
    }
}

为简单起见,您可以假设屏幕只是一个中间有一个按钮的框,当单击它们时执行导航。

我使用的伴奏版本是 0.24.1-alpha(截至本问题的最新版本),我使用的是 compose 版本 1.2.0-alpha02 和 kotlin 1.6.10。

在动画方面,我可以看到伴奏样本的唯一区别是我没有将 navController 传递到屏幕,但我不明白这可能是一个问题。

在使用应该返回到以前的系统返回方面,我真的被什么可能导致导航关闭应用程序而不是返回。在其他项目中,系统返回工作正常,但不适用于这个。伴奏导航的使用不兼容吗?我不确定。

任何帮助表示赞赏!

4

1 回答 1

0

我找到了问题的根源。

startDestination我将参数设置为这一事实navBackStackEntry?.destination?.route ?: currentRoute意味着对navBackStackEntry重组的 MyHomeNavGraph 的每次更改,因此在重组时会重置后台堆栈。

提醒自己,从多个来源复制导航时要小心!

于 2022-01-29T16:34:33.160 回答