android 使用编写导航进行导航时TopAppBar Flink

1bqhqjot  于 2023-01-28  发布在  Android
关注(0)|答案(7)|浏览(202)

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

代码:
导航:

@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)
                }
            )
        }
    }
}

待办事项列表屏幕ScaffoldTopAppBar

@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")
                        }
                    }
                }

            )
        },
[...]

添加/编辑屏幕ScaffoldTopAppBar

@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)
        )
    }
}
ezykj2lf

ezykj2lf1#

Flink 是由navigation-compose库更新版本中的默认交叉淡入淡出动画引起的。现在消除它的唯一方法(不降低依赖性)是使用伴奏动画库:
implementation "com.google.accompanist:accompanist-navigation-animation:0.20.0"
然后将普通NavHost替换为伴奏者的AnimatedNavHost,将rememberNavController()替换为rememberAnimatedNavController(),并禁用过渡动画:

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

myss37ts2#

我想我找到了解决这个问题的简单方法(适用于Compose1.4.0版)。

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

// Some Composable screnn

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

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

// Activity with NavHost

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

解决方案-不眨眼!

将您的NavHost包裹在Surface中的活动中:

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

其余的屏幕保持不变。没有 Flink 和目的地之间的过渡动画几乎和片段一样(微妙的淡入/淡出)。到目前为止,我还没有发现任何负面影响。

kdfy810k

kdfy810k3#

这是预期的行为。您正在为两个屏幕构建两个单独的应用程序栏,以便它们绑定到 Flink 。这不是正确的方式。正确的方式是将支架实际放在主Activity中,并将NavHost作为其内容放置。如果您希望修改应用程序栏,请创建变量来保存状态。然后从可组合对象中修改它们。理想情况下,然后存储在一个视图模型中。2这就是它在组合中是如何完成的。3通过变量。
谢谢

jucafojl

jucafojl4#

我遇到了同样的问题,有一个“scaffold-per-screen”架构,让我惊讶的是,帮助我的是将androidx.navigation:navigation-compose版本降低到2.4.0-alpha04

x33g5p2x

x33g5p2x5#

对于较新的库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

wfveoks0

wfveoks06#

为了不 Flink (如果您有AnimatedNavHost,则不滑动),您应该将TopAppBar放在Activity中,而不是NavHost中,否则TopAppBar只是屏幕的一部分,会像其他屏幕元素一样进行转换:

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

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

mzaanser

mzaanser7#

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

@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)
    ) {}

相关问题