I was trying out Navigation architecture component and is now having difficulties in setting the title. How do I set the title programmatically and also how it works?
<You can use this code in your fragment if you don't specify your app bar(default appbar)
(activity as MainActivity).supportActionBar?.title = "Your Custom Title"
Remember to delete the android:label
attribute in your navigation graph
Happy code ^-^
NavigationUI.setupActionBarWithNavController(this, navController)
Don't forget to specify android:label for your fragments in your nav graphs.
To navigate back:
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController, null)
}
It's actually because of:
android:label="fragment_main"
Which you have set in the xml.
So what is the proper way to show the title for
Fragment
s using Navigation Component?
setTitle()
works at this point. But, because you set label for those Fragment
s, it might show the label again when recreating the Activity
. The solution will probably be deleting android:label
and then do your things with code:
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("your title");
Or:
((AppCompatActivity) getActivity()).getSupportActionBar().setSubtitle("your subtitle");
In onCreateView()
.
Found a workaround:
interface TempToolbarTitleListener {
fun updateTitle(title: String)
}
class MainActivity : AppCompatActivity(), TempToolbarTitleListener {
...
override fun updateTitle(title: String) {
binding.toolbar.title = title
}
}
Then:
(activity as TempToolbarTitleListener).updateTitle("custom title")
Check this out too:Dynamic ActionBar title from a Fragment using AndroidX Navigation
There is a much easier way to achieve this nowadays with Kotlin and androidx.navigation:navigation-ui-ktx
:
import androidx.navigation.ui.setupActionBarWithNavController
class MainActivity : AppCompatActivity() {
private val navController: NavController
get() = findNavController(R.id.nav_host_fragment)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main)
setSupportActionBar(binding.toolbar)
setupActionBarWithNavController(navController) // <- the most important line
}
// Required by the docs for setupActionBarWithNavController(...)
override fun onSupportNavigateUp() = navController.navigateUp()
}
That's basically it. Don't forget to specify android:label
in your nav graphs.
From experience, NavController.addOnDestinationChangedListener
Seems to perform well. My example below on my MainActivity did the magic
navController.addOnDestinationChangedListener{ controller, destination, arguments ->
title = when (destination.id) {
R.id.navigation_home -> "My title"
R.id.navigation_task_start -> "My title2"
R.id.navigation_task_finish -> "My title3"
R.id.navigation_status -> "My title3"
R.id.navigation_settings -> "My title4"
else -> "Default title"
}
}
Update title with either label in navigation xml or exclude labels and set with requiresActivity().title
Supports mixing the two ways for screens with and without dynamic titles. Works for me with a Compose UI toolbar and Tabs.
val titleLiveData = MutableLiveData<String>()
findNavController().addOnDestinationChangedListener { _, destination, _ ->
destination.label?.let {
titleLiveData.value = destination.label.toString()
}
}
(requireActivity() as AppCompatActivity).setSupportActionBar(object: Toolbar(requireContext()) {
override fun setTitle(title: CharSequence?) {
titleLiveData.value = title.toString()
}
})
titleLiveData.observe(viewLifecycleOwner, {
// Update your title
})