I am using a navigation drawer .My app was working fine before that but after the code of navigation from drawer to fragment , it is showing this error! Should i change something in style?
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val navController = NavHostFragment.findNavController(nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(navController.graph)
toolbar.setupWithNavController(navController, appBarConfiguration)
}
this is my fragment code i.e. when i will click on the drawer item i will be navigated to this fragment.
Related
This question already has an answer here:
Why does navigation not work in the Navigation Drawer Activity template with version 2.4.1?
(1 answer)
Closed 26 days ago.
So I'm new to Kotlin and Android, and I clearly don't understand how we are supposed to navigate from one fragment to another using NavController. I started from the Drawer layout template available in Android Studio and I have added a few fragments to the navGraph. I can access them with the side drawer without any issue. So far so good.
Now I have added a button in my home_fragment.xml (fragment nav_home), which is the start destination (app:startDestination="#+id/nav_home") in my navigation. I added a setOnClickListener to the said button in my HomeFragment.kt in order to directly navigate to another fragment (let's say fragment2), without the drawerLayout. I am doing so with:
binding.calculatorButton.setOnClickListener {
val navHostFragment = activity?.supportFragmentManager?.findFragmentById(.R.id.nav_host_fragment_content_main) as NavHostFragment
val navController = navHostFragment.navController
navController.navigate(com.example.doughhero.R.id.nav_fragment2)
}
The problem is that I cannot acces the home_fragment from the drawer anymore: when selecting the home fragment, it goes to fragment2 (and fragment2 is highlighted in the drawer menu). But when I click the back arrow, it goes back to the home fragment (which is correct per my navigation graph).
I assume I am not navigating "correctly" to fragment2. What is the correct way of doing so, and what am I missing? Thanks!
MainActivity.kt:
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_main)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_fragment2, R.id.nav_fragment3, R.id.nav_fragment4
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_main)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
ANSWER
The navGraph should've have been provided to the appBarConfiguration:
appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
instead of
appBarConfiguration = AppBarConfiguration(setOf(R.id.nav_home,R.id.nav_fragment2,R.id.nav_fragment3, R.id.nav_fragment4), drawerLayout)
I'm not very familiar with DrawerLayout, but to me it seems you're overdoing it.
Keep in mind that a normal and simple navigation works like this:
You have an Activity that contains a FragmentContainerView or similar
You set the app:navGraph of that container.
You add the fragments to the graph and create the actions
To navigate, you just need to call findNavController().navigate(R.id.action)
If you're having trouble, I suggest that first you try to create a small navigation in a separate project instead of working directly with the drawer.
I am following the codelab https://developer.android.com/codelabs/kotlin-android-training-add-navigation/index.html#9, and I use the following code to wire up the drawer:
class MainActivity : AppCompatActivity() {
private lateinit var drawerLayout : DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
#Suppress("UNUSED_VARIABLE")
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
drawerLayout = binding.drawerLayout
val navController = findNavController(R.id.myNavHostFragment)
// To support up action and also the title, the third parameter is optional and is used
// for the hamburger menu for drawer.
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
// show the navigation drawer
NavigationUI.setupWithNavController(binding.navView, navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.myNavHostFragment)
// this is for the hamburger menu
return NavigationUI.navigateUp(navController, drawerLayout)
}
}
When the initial fragment is shown, the hamburger is shown as expected:
However, after I selected on one of the item from the drawer, e.g. About, it becomes a back/up button:
How to keep using the hamburger button instead of having it changed to an up button?
The full code from the codelab is here: https://github.com/google-developer-training/android-kotlin-fundamentals-apps/tree/master/AndroidTriviaNavigation
As per the AppBarConfiguration documentation:
NavigationUI uses an AppBarConfiguration object to manage the behavior of the Navigation button in the upper-left corner of your app's display area. The Navigation button’s behavior changes depending on whether the user is at a top-level destination.
A top-level destination is the root, or highest level destination, in a set of hierarchically-related destinations. Top-level destinations do not display an Up button in the top app bar because there is no higher level destination. By default, the start destination of your app is the only top-level destination.
When the user is at a top-level destination, the Navigation button becomes a drawer icon if the destination uses a DrawerLayout. If the destination doesn't use a DrawerLayout, the Navigation button is hidden. When the user is on any other destination, the Navigation button appears as an Up button.
Therefore if you want to have the Drawer icon appear on multiple destinations and not just the start destination, you need to create an AppBarConfiguration object with exactly what destinations you want to be top-level destinations:
// Use the IDs from your navigation graph
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.rulesFragment, R.id.aboutFragment),
drawerLayout)
Thus, your code becomes:
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration : AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
#Suppress("UNUSED_VARIABLE")
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
// Use the Kotlin extension in navigation-ui-ktx to create
// the AppBarConfiguration
appBarConfiguration = AppBarConfiguration(
setOf(R.id.rulesFragment, R.id.aboutFragment),
binding.drawerlayout)
val navController = findNavController(R.id.myNavHostFragment)
// To support up action and also the title, the third parameter is optional and is used
// for the hamburger menu for drawer.
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration)
// show the navigation drawer
NavigationUI.setupWithNavController(binding.navView, navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.myNavHostFragment)
// this is for the hamburger menu
return NavigationUI.navigateUp(navController, appBarConfiguration)
}
}
I think if you add the layout in your navdrawer_menu.xml file the hamburger icon will remain
I'm using the navigation graph to navigate and have a start screen (splash fragment) as the first fragment that is shown. The issue is that when I go to the main fragment/screen the top navigation button shows back instead of the drawer icon.
How can we get control over this? What are some options. How can I change the start destination? (if possible)
When the user is at a top-level destination, the Navigation button
becomes a drawer icon if the destination uses a DrawerLayout. If the
destination doesn't use a DrawerLayout, the Navigation button is
hidden. When the user is on any other destination, the Navigation
button appears as an Up button . To configure the Navigation button
using only the start destination as the top-level destination, create
an AppBarConfiguration object, and pass in the corresponding
navigation graph, as shown below:
Example Code
My issue is that the back button is still present when navigating to next_fragment. It should show the menu/hamburger icon.
class MainActivity : AppCompatActivity() {
private lateinit var drawerLayout: DrawerLayout
private lateinit var appBarConfiguration : AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
drawerLayout = binding.drawerLayout
val navController = this.findNavController(R.id.mainNavigationHostFragment)
NavigationUI.setupActionBarWithNavController(this, navController)
appBarConfiguration = AppBarConfiguration(setOf(R.id.nextFragment), drawerLayout)
NavigationUI.setupWithNavController(binding.mainNavigationDrawerView, navController)
val navigationHeader = binding.mainNavigationDrawerView.getHeaderView(0)
val iconButton = navigationHeader.findViewById<ImageButton>(R.id.main_nav_icon_button)
}
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.mainNavigationHostFragment)
return NavigationUI.navigateUp(navController, appBarConfiguration)
}
}
Instead of passing Navigation Graph to AppbarConfiguration, pass the id of the Fragment that should show the HamBurger icon, that way when the particular Fragment is shown, it shows home/hamburger icon instead of back icon.
That is
val appBarConfiguration = AppBarConfiguration(setOf(R.id.FAGMENT_THAT_SHOULD_SHOW_HOME_ICON), DRAWER_LAYOUT)
Update
Instead of
val navController = this.findNavController(R.id.mainNavigationHostFragment)
NavigationUI.setupActionBarWithNavController(this, navController)
appBarConfiguration = AppBarConfiguration(setOf(R.id.nextFragment), drawerLayout)
NavigationUI.setupWithNavController(binding.mainNavigationDrawerView, navController)
val navigationHeader = binding.mainNavigationDrawerView.getHeaderView(0)
val iconButton = navigationHeader.findViewById<ImageButton>(R.id.main_nav_icon_button)
Just
val navController = this.findNavController(R.id.mainNavigationHostFragment)
appBarConfiguration = AppBarConfiguration(setOf(R.id.nextFragment), drawerLayout)
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
I am trying to use Jetpack Navigation component. so navigation component will automatically handle if I want to segue from a destination to another destination when I click a menu in the navigation drawer
but I want to perform an action if a menu is clicked, say for example if a menu in drawer is clicked then I want to show a toast message.
in old way, ie using fragment transaction, I can easily check from onNavigationItemSelected, but I am no longer find that method
so how to do that in navigation component ?
I have tried to check onDestinationChanged , but it doesn't work
override fun onDestinationChanged(controller: NavController, destination: NavDestination, arguments: Bundle?) {
if (destination.id == R.id.my_destination {
// show toast in here
// but it doesn't work
}
}
here is my MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var navController : NavController
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
appBarConfiguration = AppBarConfiguration(setOf(
R.id.destination_share,
R.id.destination_message,
R.id.destination_chat),
drawer_layout
)
// init nav controller
navController = Navigation.findNavController(this,R.id.nav_host_fragment)
// set toolbar
setSupportActionBar(toolbar)
// set up navigation drawer
NavigationUI.setupActionBarWithNavController(this,navController, appBarConfiguration)
NavigationUI.setupWithNavController(navigation_view,navController)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController,appBarConfiguration)
}
}
You can handle Menu clicks as following
navView.menu.findItem(R.id.logout)
.setOnMenuItemClickListener { menuItem: MenuItem? ->
// write your code here
true
}
Have you tried using
bottom_nav_view.setOnNavigationItemSelectedListener {
if (destination.id == R.id.my_destination {
// show toast in here
// but it doesn't work
}
}
So, I use the latest version of androidstudio and kotlin.
I created a bottom navigation activity project, and I use the activity with the drefault generated code.
I would like to open/replace a fragment from another fragment by button.
But the previous fragment doesn't disappear, when the new fragment is appear, so both are visible.
I read a lot, but I don't know the solution, please help me with some advice.
This is my MainActivity
override fun onCreate(savedInstanceState: Bundle ? ) {
super.onCreate(savedInstanceState)
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_advertisements, R.id.navigation_own_advertisements, R.id.navigation_chat, R.id.navigation_party, R.id.navigation_settings))
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
And this is my fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle ? ) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener {
activity!!.supportFragmentManager
.beginTransaction()
.replace(R.id.nav_host_fragment, ChatFragment())
.commit()
}
}