Karthick
10/09/2020, 3:38 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 AMnavController.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 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 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