Jetpack Compose 具有动态操作的 TopAppBar

2023-11-21

@Composable
fun TopAppBar(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    navigationIcon: @Composable (() -> Unit)? = null,
    actions: @Composable RowScope.() -> Unit = {},
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    elevation: Dp = AppBarDefaults.TopAppBarElevation
)

操作:@Composable RowScope.() -> Unit = {}

使用场景:使用 Compose Navigation 切换到不同的“屏幕”,因此 TopAppBar 操作也会相应改变。例如。内容屏幕的共享按钮、列表屏幕的过滤按钮

尝试将状态传递给 TopAppBar 的 actions 参数,但无法保存 lambda 块remember功能。

val (actions, setActions) = rememberSaveable { mutableStateOf( appBarActions ) }

想要动态更改应用栏操作内容。有什么办法可以做到吗?


这是我使用的方法,但我对撰写还很陌生,所以我不能确定这是正确的方法。

假设我有 2 个屏幕:ScreenA 和 ScreenB 它们由 MainActivity 屏幕处理。 这是我们的主要活动:

@ExperimentalComposeUiApi
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalMaterial3Api::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            CoolDrinksTheme {
                val navController = rememberNavController()

                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    var appBarState by remember {
                        mutableStateOf(AppBarState())
                    }

                    Scaffold(
                        topBar = {
                            SmallTopAppBar(
                                title = {
                                    Text(text = appBarState.title)
                                },
                                actions = {
                                    appBarState.actions?.invoke(this)
                                }
                            )
                        }
                    ) { values ->
                        NavHost(
                            navController = navController,
                            startDestination = "screen_a",
                            modifier = Modifier.padding(
                                values
                            )
                        ) {
                            composable("screen_a") {
                                ScreenA(
                                    onComposing = {
                                        appBarState = it
                                    },
                                    navController = navController
                                )
                            }
                            composable("screen_b") {
                                ScreenB(
                                    onComposing = {
                                        appBarState = it
                                    },
                                    navController = navController
                                )
                            }
                        }
                    }
                }
            }
        }
    }
}

正如您所看到的,我使用了一个类的可变状态,它代表了 MainActivity 的状态(TopAppBar 是在其中声明和组合的),在此示例中,有 TopAppBar 的标题和操作。

这种可变状态是通过在每个屏幕的组合内部调用的回调函数来设置的。

在这里你可以看到屏幕

@Composable
fun ScreenA(
    onComposing: (AppBarState) -> Unit,
    navController: NavController
) {

    LaunchedEffect(key1 = true) {
        onComposing(
            AppBarState(
                title = "My Screen A",
                actions = {
                    IconButton(onClick = { }) {
                        Icon(
                            imageVector = Icons.Default.Favorite,
                            contentDescription = null
                        )
                    }
                    IconButton(onClick = { }) {
                        Icon(
                            imageVector = Icons.Default.Filter,
                            contentDescription = null
                        )
                    }
                }
            )
        )
    }


    Column(
        modifier = Modifier
            .fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Screen A"
        )
        Button(onClick = {
            navController.navigate("screen_b")
        }) {
            Text(text = "Navigate to Screen B")
        }
    }
}

和屏幕

@Composable
fun ScreenB(
    onComposing: (AppBarState) -> Unit,
    navController: NavController
) {

    LaunchedEffect(key1 = true) {
        onComposing(
            AppBarState(
                title = "My Screen B",
                actions = {
                    IconButton(onClick = { }) {
                        Icon(
                            imageVector = Icons.Default.Home,
                            contentDescription = null
                        )
                    }
                    IconButton(onClick = { }) {
                        Icon(
                            imageVector = Icons.Default.Delete,
                            contentDescription = null
                        )
                    }
                }
            )
        )
    }


    Column(
        modifier = Modifier
            .fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Screen B"
        )
        Button(onClick = {
            navController.popBackStack()
        }) {
            Text(text = "Navigate back to Screen A")
        }
    }
}

最后这是我们状态的数据类:

data class AppBarState(
    val title: String = "",
    val actions: (@Composable RowScope.() -> Unit)? = null
)

通过这种方式,您可以在主活动中声明一个动态应用程序栏,但每个屏幕都负责处理应用程序栏的内容。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jetpack Compose 具有动态操作的 TopAppBar 的相关文章

随机推荐