In my mainactivity I have:
val navController = findNavController(R.id.navhostApp)
val navView = findViewById<NavigationView>(R.id.nvAppDrawer)
drawerLayout = findViewById<DrawerLayout>(R.id.drawerLayout)
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
NavigationUI.setupWithNavController(navView, navController)
I have a navcontroller (drawer style) as my main app navigation, and then in one of the hosted fragments another nav controller for a bottom navigation. I want to have these fragments update the action bar title but the title is only for the container fragment. Is there a way to programmatically get the actionbar to change the title?
I've tried using
requireActivity and actionBar.title but it returns null.
And of course after posting I figure it out.
val actionBar = (requireActivity() as MainActivity).supportActionBar
Then actionBar.title = "Title"
Related
I am working on adding a toolbar title in the NavGraph. I used android:label"sample tile" in the NavGraph, but its not updating the toolbar with the label.
Tried using android:label in the NavGraph, but its not updating the title of the toolbar.
Using android:label alone won't be fully integrated with jetpack navigation.
In documentation:
NavigationUI contains methods that automatically update content in
your top app bar as users navigate through your app. For example,
NavigationUI uses the destination labels from your navigation graph to
keep the title of the top app bar up-to-date.
So, you need to configure the top app bar to work with NavigationUI and this is done through setupWithNavController().
This section in documentations provides an example:
// Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
setContentView(R.layout.activity_main)
...
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(navController.graph)
findViewById<Toolbar>(R.id.toolbar)
.setupWithNavController(navController, appBarConfiguration)
}
// Java
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
...
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph()).build();
Toolbar toolbar = findViewById(R.id.toolbar);
NavigationUI.setupWithNavController(
toolbar, navController, appBarConfiguration);
}
I'm implementing Navigation Drawer using androidx.navigation.ui.
Based on Android Studio's Navigation Drawer Activity Template, when I put in onDrawerSlide that works according to the drawer animation, the topLevelDesitnationIds set in AppBarConfigration is ignored, and the navigation button (not the drawer icon, but the back button) will be displayed in the non-topLevel Fragment. Even if I press it, the drawer will come out every time.
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_main)
//-- START : It will come out a drawer menu regardless of the fragment stack
class LocalActionBarDrawerToggle : ActionBarDrawerToggle(this,
drawerLayout,
binding.appBarMain.toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close) {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
// do something
super.onDrawerSlide(drawerView, slideOffset)
}
}
val drawerToggle = LocalActionBarDrawerToggle()
drawerLayout.addDrawerListener(drawerToggle)
drawerToggle.syncState()
//-- END
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
For non-top level Fragments, the navigation button is a back button instead of a drawer icon, so I think it's simply overriding the motion control. Please give me some advice.
Top app bar
Caution: If you pass a Toolbar as the argument to setSupportActionBar(), the ActionBar assumes complete ownership of that Toolbar and you must not use any Toolbar APIs after that call. You can use the support for the ActionBar to connect the ActionBar to NavController.
Make sure Toolbar APIs are called before setSupportActionBar().
I am using a navigation graph in my app. I have a bottom navigation bar. I am staring my navigation components with the following in my Main Activity:
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(setOf(
R.id.navigation_artist_list, R.id.navigation_dashboard, R.id.navigation_notifications))
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
This starts my navigation components, which inflate the fragement setup in R.id.navigation_artist_list.
From an observer in that fragment I am navigating to another fragment with:
viewModel.selectedAlbum.observe(this, Observer { artist ->
val action = HomeFragmentDirections.actionNavigationHomeToAlbumFragment(artist)
root.findNavController().navigate(action)
})
However, none of the mechanisms available for navigation work properly. The back button just refreshes the fragment and populates the list in the fragment again. The back button on the action bar is completely ignored.
Do I need to do something else to have the proper back button behavior, to go back to the previous fragment?
In yout MainActivity, override the onSupportNavigateUp() method to call navigateUp() in the navigation controller
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.nav_host_fragment)
return navController.navigateUp()
}
Is it possible to use Android Navigation component/graph in the single activity app in which each fragment has its own toolbar?
Also, container activity has a navigation drawer that needs setup with toolbar and navigation controller, but at the time of activity creation I don't have yet the toolbar.
I am using this code (called in onCreate)
private fun setupNavigation() {
// val toolbar = findViewById<Toolbar>(R.id.toolbar);
// setSupportActionBar(toolbar);
// supportActionBar!!.setDisplayHomeAsUpEnabled(true);
// supportActionBar!!.setDisplayShowHomeEnabled(true);
val drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout);
val navigationView = findViewById<NavigationView>(R.id.drawer_navigation_view);
val navController = Navigation.findNavController(this, R.id.navigation_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
NavigationUI.setupWithNavController(navigationView, navController)
navigationView.setNavigationItemSelectedListener(this)
}
But since I don't have toolbar at the time it throws an error (ActionBar.setTitle called on a null object).
Is it possible to have this, or I need to drop the idea to use navigation component in this case?
The only requirement is that you call setupActionBarWithNavController after you call setSupportActionBar(). If you're doing that in your Fragment, then just call setupActionBarWithNavController directly after that.
For example, in your Fragment:
private fun onViewCreated(view: View, bundle: savedInstanceState) {
val toolbar = view.findViewById<Toolbar>(R.id.toolbar);
// Set the Toolbar as your activity's ActionBar
requireActivity().setSupportActionBar(toolbar);
// Find the activity's DrawerLayout
val drawerLayout = requireActivity().findViewById<DrawerLayout>(R.id.drawer_layout);
// Find this Fragment's NavController
val navController = NavHostFragment.findNavController(this);
// And set up the ActionBar
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
}
There's also a separate NavigationUI.setupWithNavController() method that takes a Toolbar. This would be appropriate if you aren't actually using any of the other ActionBar APIs.
I've been building a sample app with the new Navigation Architecture Component in combination with a Nav Drawer.
I have my navigation graph created, my fragments created, and the nav drawer displaying and navigating between the fragments mostly as expected. The problem is that each time I select an item from the nav drawer, it adds the fragment to the stack, instead of popping the existing one and adding the new one. This means that if I navigate to a new fragment, I've created a back stack and tapping the menu button in the action bar pops the latest fragment off the stack, instead of opening the nav drawer as I would expect. Here is my code:
private fun configureNavigation() {
navDrawerLayout = findViewById(R.id.navigation_drawer_layout)
navView = findViewById(R.id.navigationView)
navController = Navigation.findNavController(this, R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.workouts_fragment, R.id.create_workout_fragment, R.id.workout_history_fragment),
navDrawerLayout
)
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration)
NavigationUI.setupWithNavController(navView, navController)
navView.setNavigationItemSelectedListener(this)
}
override fun onSupportNavigateUp() = navController.navigateUp()
override fun onNavigationItemSelected(menuItem: MenuItem): Boolean {
menuItem.isChecked = true
navDrawerLayout.closeDrawers()
#IdRes val destination: Int = when (menuItem.itemId) {
R.id.workouts_nav_drawer_item -> R.id.workouts_fragment
R.id.create_workout_nav_drawer_item -> R.id.create_workout_fragment
R.id.workout_history_nav_drawer_item -> R.id.workout_history_fragment
else -> {
throw IllegalArgumentException("Attempting to process an unrecognized menuItem id in the navigation drawer layout")
}
}
if (destination != currentDestination) {
currentDestination = destination
navController.navigate(destination)
}
return true
}
I discovered there were two requirements to get the nav drawer, nav graph, and action bar completely in sync with my desired behaviour.
The first is the AppBarConfiguration. I had to create an app bar configuration containing a set of top level destinations (the top level fragments in the nav drawer).
The second aspect was to make sure that in onSupportNavigateUp() function to include the app bar configuration in the call as such: `navController.navigateUp(appBarConfiguration).
Once I had done these two things, everything worked as expected, and the nav drawer, action bar, and up button all worked in sync without unnecessarily adding fragments to the stack.