'Jetpack Compose TopAppBar with dynamic actions

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

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

Usage Scenario: Using Compose Navigation to switch to different "screens", so the TopAppBar actions will be changed accordingly. Eg. Share buttons for content screen, Filter button for listing screen

Tried passing as a state to the TopAppBar's actions parameter, but having trouble to save the lambda block for the remember function.

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

Want to change the app bar actions content dynamically. Any way to do it?



Solution 1:[1]

First you need to add navigation dependency on you jetpack compose projects.

You can read the doc from this https://developer.android.com/jetpack/compose/navigation

def nav_version = "2.4.1"
implementation "androidx.navigation:navigation-compose:$nav_version"

Then define your screen in sealed class:

sealed class Screen(var icon: ImageVector, var route: String) {
    object ContentScreen: Screen(Icons.Default.Home, "home")
    object ListingScreen: Screen(Icons.Default.List, "list")
}

and this is the navigation function look like

@Composable
fun Navigation(paddingValues: PaddingValues, navController: NavHostController) {
    NavHost(navController, startDestination = Screen.ContentScreen.route, modifier = Modifier.padding(paddingValues)) {
        composable(Screen.ContentScreen.route) {
            //your screen content
        }
        composable(Screen.ListingScreen.route) {
            //your listing screen here
        }
    }
}

Finally in your mainactivity class

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TestAppTheme {
                val navController = rememberNavController()
                val navBackStackEntry by navController.currentBackStackEntryAsState()
                val currentRoute = navBackStackEntry?.destination?.route
                Scaffold(
                    topBar = {
                        TopAppBar(title = { Text(text = "main screen") }, actions = {
                            if (currentRoute == Screen.ContentScreen.route) {
                                //your share button action here
                            } else if (currentRoute == Screen.ListingScreen.route) {
                                //your filter button here
                            } else {
                                //other action
                            }
                        })
                    }
                ) {
                    Navigation(paddingValues = it, navController = navController)
                }
            }
        }
    }

I'm so sorry if the explanation to sort, because the limitation of my English

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 marc_s