繁体   English   中英

使用 Compose Navigation 导航时 TopAppBar 闪烁

[英]TopAppBar flashing when navigating with Compose Navigation

我有 2 个屏幕,它们都有自己的ScaffoldTopAppBar 当我使用 Jetpack Navigation Compose 库在它们之间导航时,应用栏会闪烁。 为什么会发生这种情况,我怎样才能摆脱这种情况?

在此处输入图像描述

代码:

导航:

@Composable
fun TodoNavHost(
    navController: NavHostController,
    modifier: Modifier = Modifier
) {
    NavHost(
        navController = navController,
        startDestination = TodoScreen.TodoList.name,
        modifier = modifier
    ) {
        composable(TodoScreen.TodoList.name) {
            TodoListScreen(
                onTodoEditClicked = { todo ->
                    navController.navigate("${TodoScreen.AddEditTodo.name}?todoId=${todo.id}")
                },
                onFabAddNewTodoClicked = {
                    navController.navigate(TodoScreen.AddEditTodo.name)
                }
            )
        }
        composable(
            "${TodoScreen.AddEditTodo.name}?todoId={todoId}", 
            arguments = listOf(
                navArgument("todoId") {
                    type = NavType.LongType
                    defaultValue = -1L
                }
            )
        ) {
            AddEditTodoScreen(
                onNavigateUp = {
                    navController.popBackStack() 
                },
                onNavigateBackWithResult = { result ->
                    navController.navigate(TodoScreen.TodoList.name)
                }
            )
        }
    }
}

带有TopAppBar的 Todo 列表屏幕Scaffold

@Composable
fun TodoListBody(
    todos: List<Todo>,
    todoExpandedStates: Map<Long, Boolean>,
    onTodoItemClicked: (Todo) -> Unit,
    onTodoCheckedChanged: (Todo, Boolean) -> Unit,
    onTodoEditClicked: (Todo) -> Unit,
    onFabAddNewTodoClicked: () -> Unit,
    onDeleteAllCompletedConfirmed: () -> Unit,
    modifier: Modifier = Modifier,
    errorSnackbarMessage: String = "",
    errorSnackbarShown: Boolean = false
) {

    var menuExpanded by remember { mutableStateOf(false) }
    var showDeleteAllCompletedConfirmationDialog by rememberSaveable { mutableStateOf(false) }

    Scaffold(
        modifier,
        topBar = {
            TopAppBar(
                title = { Text("My Todos") },
                actions = {
                    IconButton(
                        onClick = { menuExpanded = !menuExpanded },
                        modifier = Modifier.semantics {
                            contentDescription = "Options Menu"
                        }
                    ) {
                        Icon(Icons.Default.MoreVert, contentDescription = "Show menu")
                    }
                    DropdownMenu(
                        expanded = menuExpanded,
                        onDismissRequest = { menuExpanded = false }) {
                        DropdownMenuItem(
                            onClick = {
                                showDeleteAllCompletedConfirmationDialog = true
                                menuExpanded = false
                            },
                            modifier = Modifier.semantics {
                                contentDescription = "Option Delete All Completed"
                            }) {
                            Text("Delete all completed")
                        }
                    }
                }

            )
        },
[...]

使用TopAppBar添加/编辑屏幕Scaffold

@Composable
fun AddEditTodoBody(
    todo: Todo?,
    todoTitle: String,
    setTitle: (String) -> Unit,
    todoImportance: Boolean,
    setImportance: (Boolean) -> Unit,
    onSaveClick: () -> Unit,
    onNavigateUp: () -> Unit,
    modifier: Modifier = Modifier
) {
    Scaffold(
        modifier,
        topBar = {
            TopAppBar(
                title = { Text(todo?.let { "Edit Todo" } ?: "Add Todo") },
                actions = {
                    IconButton(onClick = onSaveClick) {
                        Icon(Icons.Default.Save, contentDescription = "Save Todo")
                    }
                },
                navigationIcon = {
                    IconButton(onClick = onNavigateUp) {
                        Icon(Icons.Default.ArrowBack, contentDescription = "Back")
                    }
                }
            )
        },
    ) { innerPadding ->
        BodyContent(
            todoTitle = todoTitle,
            setTitle = setTitle,
            todoImportance = todoImportance,
            setImportance = setImportance,
            modifier = Modifier.padding(innerPadding)
        )
    }
}

我想我找到了解决该问题的简单方法(适用于 Compose 1.4.0 版)。

我的设置 - 闪烁

我所有的屏幕都有自己的工具栏包裹在脚手架中:

// Some Composable screnn

Scaffold(
    topBar = { TopAppBar(...) }
) {
    ScreenContent()
}

拥有导航主机的主要活动定义如下:

// Activity with NavHost

setContent {
    AppTheme {
        NavHost(...) { }
    }
}

解决方案 - 不要眨眼!

将 NavHost 包裹在 Surface 的活动中:

setContent {
    AppTheme {
        Surface {
            NavHost(...) { }
        }
    }
}

Rest 的屏幕保持不变。 目的地之间没有闪烁和过渡 animation 几乎与片段相同(微妙的淡入/淡出)。 到目前为止,我还没有发现任何负面影响。

我遇到了同样的问题,有一个“每个屏幕的脚手架”架构。 令我惊讶的是,将androidx.navigation:navigation-compose版本降低到2.4.0-alpha04

为了不闪烁(或者如果你有AnimatedNavHost则滑动)你应该把TopAppBar放在活动中和NavHost之外,否则TopAppBar只是屏幕的一部分并且像其他屏幕元素一样进行转换:

// Activity with your navigation host
setContent {
    MyAppTheme {
        Scaffold(
            topBar = { TopAppBar(...) }
        ) { padding ->
            TodoNavHost(padding, ...) { }
        }
    }
}

来自包含TopAppBarScaffoldpadding参数,您应该将其传递给NavHost并在屏幕中使用它,就像您在示例中所做的那样

这是预期的行为。 您正在为两个屏幕构建两个单独的应用栏,因此它们一定会闪烁。 这不是正确的方法。 正确的方法是将脚手架实际放在您的主要活动中,并将 NavHost 作为其内容放置。 如果您希望修改应用栏,请创建变量以保持状态。 然后从 Composables 修改它们。 理想情况下,然后将其存储在视图模型中。 这就是在撰写中完成的方式。 通过变量。

谢谢

闪烁是由更新版本的navigation-compose库中的默认交叉淡入淡出动画引起的。 现在摆脱它的唯一方法(不降级依赖项)是使用Accompanist动画库:

implementation "com.google.accompanist:accompanist-navigation-animation:0.20.0"

然后替换 Accompanist 的AnimatedNavHost的正常NavHost并禁用转换动画:

AnimatedNavHost(
        navController = navController,
        startDestination = bottomNavDestinations[0].fullRoute,
        enterTransition = { _, _ -> EnterTransition.None },
        exitTransition = { _, _ -> ExitTransition.None },
        popEnterTransition = { _, _ -> EnterTransition.None },
        popExitTransition = { _, _ -> ExitTransition.None },
        modifier = modifier,
    ) {
        [...}
    }

使用较新的库implementation "com.google.accompanist:accompanist-navigation-animation:0.24.1-alpha" ,您需要拥有这样的AnimatedNavHost

AnimatedNavHost(
            navController = navController,
            startDestination = BottomNavDestinations.TimerScreen.route,
            enterTransition = { EnterTransition.None },
            exitTransition = { ExitTransition.None },
            popEnterTransition = { EnterTransition.None },
            popExitTransition = { ExitTransition.None },
            modifier = Modifier.padding(innerPadding)

rememberNavController()替换为rememberAnimatedNavController()

NavHost替换为AnimatedNavHost

import androidx.navigation.compose.navigation替换为import com.google.accompanist.navigation.animation.navigation

import androidx.navigation.compose.composable替换为import com.google.accompanist.navigation.animation.composable

除了删除动画之外,您还可以更改动画,例如:

@Composable
private fun ScreenContent() {
    val navController = rememberAnimatedNavController()
    val springSpec = spring<IntOffset>(dampingRatio = Spring.DampingRatioMediumBouncy)
    val tweenSpec = tween<IntOffset>(durationMillis = 2000, easing = CubicBezierEasing(0.08f, 0.93f, 0.68f, 1.27f))
    ...
    ) { innerPadding ->
        AnimatedNavHost(
            navController = navController,
            startDestination = BottomNavDestinations.TimerScreen.route,
            enterTransition = { slideInHorizontally(initialOffsetX = { 1000 }, animationSpec = springSpec) },
            exitTransition = { slideOutHorizontally(targetOffsetX = { -1000 }, animationSpec = springSpec) },
            popEnterTransition = { slideInHorizontally(initialOffsetX = { 1000 }, animationSpec = tweenSpec) },
            popExitTransition = { slideOutHorizontally(targetOffsetX = { -1000 }, animationSpec = tweenSpec) },
            modifier = Modifier.padding(innerPadding)
    ) {}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM