Android:如何防止 Scaffolds 顶部应用栏在 Jetpack Compose Navigation 中重绘?

Gam*_*015 7 android android-architecture-navigation android-jetpack-navigation android-jetpack-compose android-jetpack-compose-material3

当在两个屏幕之间导航时,每个屏幕都有一个带有 TopAppBar 的脚手架,TopAppBar 会以动画方式退出 UI 并返回。(在我的示例中短暂的白色闪烁,就像按钮动画一样)

我想这种行为是预期的,因为 compose 无法知道,这两者应该被视为相同。

有没有什么方法可以防止这种行为,而不将标题状态提升到 MainNavigation 可组合项,以便仅在导航上重绘标题?我认为在 flutter 中几乎所有小部件都有一个名为“key”的属性,jetpack compose 中也有类似的属性吗?

对于这个小例子来说,这很好,但是当有一个更复杂的导航图时,我担心 MainNavigation 会因属于其他地方的语义而过载,例如加载数据以显示项目名称......

代码

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            UnwelcomeNavAnimationTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    MainNavigation()
                }
            }
        }
    }
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainNavigation() {
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "screen1") {
        composable("screen1") {
            Scaffold(
                topBar = {
                    TopAppBar(title = {
                        Text(
                            text = "Screen 1",
                            color = MaterialTheme.colorScheme.onPrimary
                        )
                    }, colors = TopAppBarDefaults.smallTopAppBarColors(
                        containerColor = MaterialTheme.colorScheme.primary
                    ))
                }
            ) {
                Button(
                    onClick = {
                        navController.navigate("screen2")
                    },
                    modifier = Modifier.padding(it)
                ) {
                    Text(text = "Switch")
                }
            }
        }
        composable("screen2") {
            Scaffold(
                topBar = {
                    TopAppBar(title = {
                        Text(
                            text = "Screen 2",
                            color = MaterialTheme.colorScheme.onPrimary
                        )
                    }, colors = TopAppBarDefaults.smallTopAppBarColors(
                        containerColor = MaterialTheme.colorScheme.primary
                    ))
                }
            ) {
                Button(
                    onClick = {
                        navController.navigate("screen1")
                    },
                    modifier = Modifier.padding(it)
                ) {
                    Text(text = "Switch")
                }
            }
        }
        // TODO: Add more destinations
    }
}
Run Code Online (Sandbox Code Playgroud)

依赖关系

implementation 'androidx.navigation:navigation-compose:2.5.3'
Run Code Online (Sandbox Code Playgroud)

ura*_*reo 2

您需要从 NavHost 中删除应用程序栏,因此您将使用单个脚手架。为了正确显示它们,您需要首先检查当前路线,然后根据它显示应用栏。

val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route

Scaffold(
    topBar = {
        when (currentRoute) {
            "screen1" -> {
                TopAppBar(title = {
                    Text(
                        text = "Screen 1",
                        color = MaterialTheme.colorScheme.onPrimary
                    )
                }, colors = TopAppBarDefaults.smallTopAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primary
                ))
            }
            
            "screen2" -> {
                TopAppBar(title = {
                    Text(
                        text = "Screen 2",
                        color = MaterialTheme.colorScheme.onPrimary
                    )
                }, colors = TopAppBarDefaults.smallTopAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primary
                ))
            }
            
            else -> {
                // mandatory blank app bar to show when the start destination hasn't been yet navigated
                TopAppBar(title = {
                    Text(
                        text = "",
                        color = MaterialTheme.colorScheme.onPrimary
                    )
                }, colors = TopAppBarDefaults.smallTopAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primary
                ))
            }
        }
    }
) {
    NavHost(
        navController = navController,
        startDestination = "screen1",
        modifier = Modifier.padding(it)
    ) {
        composable("screen1") {
            Button(
                onClick = {
                    navController.navigate("screen2")
                },
                modifier = Modifier.padding(it)
            ) {
                Text(text = "Switch")
            }
        }
        composable("screen2") {
            Button(
                onClick = {
                    navController.navigate("screen1")
                },
                modifier = Modifier.padding(it)
            ) {
                Text(text = "Switch")
            }
        }
        // TODO: Add more destinations
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢您的回答!虽然这对于小型应用程序来说没问题,但我担心解决方案的扩展性;在更复杂的导航图的情况下,MainNavigation 可能会因属于其他地方的语义而过载,例如加载数据以将项目名称显示为标题,并且屏幕的内容被有效地分割为多个部分;我更喜欢一个解决方案,其中每个屏幕都可以定义它的标题以及可能的脚手架的其他部分,如操作、浮动操作按钮等……; (7认同)