Karthick
10/09/2020, 3:38 AMIan Lake
10/09/2020, 3:39 AMIan Lake
10/09/2020, 3:39 AMAfzal Najam
10/09/2020, 5:02 AMIan Lake
10/09/2020, 5:04 AMAfzal Najam
10/09/2020, 5:05 AMArchie
10/09/2020, 5:45 AMAfzal Najam
10/09/2020, 6:46 AMmaven { url = '<https://androidx.dev/snapshots/builds/6893483/artifacts/ui/repository>' }
implementation "androidx.compose.navigation:navigation:1.0.0-SNAPSHOT"Archie
10/09/2020, 6:58 AMArchie
10/09/2020, 12:34 PMnavController.addOnDestinationChangedListener {
...
// Hide/show shared UI here
...
}
We usually do this for switching persistent AppBar or any shared UI across screens. Is this still the case for Compose or will Compose Navigation Component introduce something different?Afzal Najam
10/09/2020, 1:37 PMcurrentBackstackEntryAsState function or something like that. Since we don't have listeners or classes much in the UI anymore, a state would be a compose-like approach. I'm guessing that all the rest of the functionality will get polished over time according to usage.Archie
10/09/2020, 2:28 PMIan Lake
10/09/2020, 3:13 PMArchie
10/12/2020, 9:58 AMAppBar or any "shared UI across screen" be defined inside each destination like so?
NavHost(startDestination = "Start") {
composable("Start") {
Scaffold(
topBar = { MyCustomerAppBar() }
) {
....
}
}
composable("Screen2") {
Scaffold(
topBar = { MyCustomerAppBar() }
) {
....
}
}
composable("Screen3") {
Scaffold(
topBar = { DifferentAppBar() }
) {
....
}
}
}Ian Lake
10/12/2020, 4:21 PMNavController) to outside of the `NavHost`:
val navController = rememberNavController()
val currentBackStackEntry = navController.currentBackStackEntryAsState()
Scaffold(
topBar = {
// Use whatever logic you want here
if (currentBackStackEntry?.value?.arguments?.getBoolean("showAppBar") == true) {
MyCustomerAppBar()
} else {
DifferentAppBar()
}
) {
NavHost(navController, startDestination = "start") {
composable("start") {
}
}
}Archie
10/13/2020, 12:53 PMArchie
10/18/2020, 2:11 PMval navController = rememberNavController()
val currentBackStackEntry = navController.currentBackStackEntryAsState()
Scaffold(
topBar = {
// Use whatever logic you want here
if (currentBackStackEntry?.value?.arguments?.getBoolean("showAppBar") == true) {
MyCustomerAppBar()
} else {
DifferentAppBar()
}
) {
NavHost(navController, startDestination = "start") {
composable("start") {
}
}
}
The app bar is shared across screens. Assuming that the app bar have app bar menu and when clicked, depending on the current screen it triggers a different action. In the current way of doing this with fragments, we do something like:
class MyFragment : Fragment() {
override fun onCreate(context: Context) {
....
setHasOptionsMenu(true)
....
}
// To set the menu
override fun onCreateOptionsMenu(menu: Menu) {
....
menuInflater.inflate(R.menu.myMenu, menu)
....
}
// to Recieve the event when the menu is clicked
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handler action when menu item is clicked
}
....
}
How should the same thing be handled in compose? Since the AppBar is now in the scope of the current View. The only way I can think of is doing something like this in compose.
val navController = rememberNavController()
val currentBackStackEntry = navController.currentBackStackEntryAsState()
// create a state which I could pass down and listen to when value gets set
val someState = remember { SomeState() }
Scaffold(
topBar = {
Button(
onClick = { someState.value = SomeValue() }, // Set the value of the state
content = { Text("Click ME!") },
)
) {
NavHost(navController, startDestination = "start") {
composable("start") {
MyScreen(someState) // Check value of someState inside My Screen to know when the button is clicked.
}
}
}
But I feel like this is the wrong way.Ian Lake
10/18/2020, 2:54 PMArchie
10/18/2020, 5:37 PMArchie
10/18/2020, 5:46 PMviewModel() inside a composable(...) {} the ViewModel is now scoped to that composable(...) instead of the Activity. as seen in this code snippet inside NavHost
...
if (destination is ComposeNavigator.Destination) {
// while in the scope of the composable, we provide the navBackStackEntry as the
// ViewModelStoreOwner and LifecycleOwner
Providers(
AmbientNavController provides navController,
ViewModelStoreOwnerAmbient provides currentNavBackStackEntry!!,
LifecycleOwnerAmbient provides currentNavBackStackEntry!!,
children = destination.content
)
}
....
I was wondering If is also possible to scope a ViewModel across multiple composable(...) just like how navGraphViewModels(...) work?Ian Lake
10/18/2020, 5:53 PMviewModel() isn't doing anything special, just calling through to ViewModelProvider with the right ViewModelStoreOwner. Which is the same thing navGraphViewModels() does: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:navigation/navigation-fragment-ktx/src/main/java/androidx/navigation/NavGraphViewModelLazy.kt;l=56Archie
10/19/2020, 10:27 AMviewModel() across composable(...){...} will still give the same ViewModel since its using the current backStackEntry.viewModelStore. did i get it right?Ian Lake
10/19/2020, 3:11 PMViewModelProvider directlyArchie
10/19/2020, 3:24 PM