How to handle up button inside fragment using Navigation Components - android

I am making a simple note taking app, I have 2 fragments with navigation component, one fragment has a list of notes and the other is for editing or creating a new note.
In MainActivity I added
val navController = this.findNavController(R.id.host_fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
and then override onSupportNavigateUp()
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.host_fragment)
return navController.navigateUp()
}
In NoteEditFragment
requireActivity().onBackPressedDispatcher.addCallback(this) {
saveOrUpdateNote(noteId, note)
}
now it all works well when pressing the "back button" in the device, However onBackPressedDispatcher.addCallback() is note triggered when I press the "up button" the one on the top left of the screen.
My question is : How do I handle this up button from my NoteEditFragment?
Thanks in advance

Finally, I found the solution.
First In the activity onCreate method I had to connect the navigation like I did:
val navController = this.findNavController(R.id.host_fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
Then still in MainActivity override onSupportNavigateUp() :
override fun onSupportNavigateUp(): Boolean
{
val navController = this.findNavController(R.id.host_fragment)
return navController.navigateUp()
}
Then In the Fragment onCreateView I had to enable option menu:
setHasOptionsMenu(true)
then in the fragment I overridden onOptionsItemSelected :
override fun onOptionsItemSelected(item: MenuItem): Boolean
{
// handle the up button here
return NavigationUI.onNavDestinationSelected(item!!,
view!!.findNavController())
|| super.onOptionsItemSelected(item)
}
Note: I think if you have more than one option menu, then I think you have to do a when (item) statement to check what option has been chosen.
Also if you want to handle the device back button then you can do like this in your fragment onCreateViewMethod :
requireActivity().onBackPressedDispatcher.addCallback(this)
{
// handle back button
// change this line to whatever way you chose to navigate back
findNavController().navigate(NoteEditFragmentDirections.actionNoteEditFragmentToNoteListFragment())
}

I think the accepted answer is a bit messy. So, i found a clean code. It is perfect for my use case as i don't need to do anything special when the device back button is pressed. Therefore, anyone here with the same requirements can follow my code.
In onCreate of MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(navController.graph)
// Check if androidx.navigation.ui.NavigationUI.setupActionBarWithNavController is imported
// By default title in actionbar is used from the fragment label in navigation graph
// To use the app name, remove label else if you want to add customized label specify it there
setupActionBarWithNavController(this, navController, appBarConfiguration)
...
}
Again, in the MainActivity itself:
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.fragment)
// Check if androidx.Navigation.ui navigateUp is imported and used
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
I have added comments for better understanding. If you think the answer is helpful then please upvote. Thank You. Happy Development :)
EDIT 1:
No need to use supportActionBar.setDisplayHomeAsUpEnabled(true) in the fragments. AppBarConfiguration will take care of it.

if you use noActionBar themes and you want to use your own toolbar as an actionBar for the fragment, you can use this method
in the host activity
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.navHostFragment).navigateUp()
}
in the onCreateView of the fragment
(activity as AppCompatActivity).setSupportActionBar(binding.toolbar)
(activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)

in very simple way you just need to set the supportNavigateUp on the Activity.
in MainActivity:
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
in my case its worked

Related

lateinit property navController has not been initialized

I was following the official developer.android.com code labs when I encounter this issue
In the MainActivity, you should already have code to set up the app bar (also known as action bar) with the nav controller. Make navController a class variable so you can use it in another method.
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
}
Within the same class, add code to override the onSupportNavigateUp() function. This code will ask the navController to handle navigating up in the app. Otherwise, fall back to back to the superclass implementation (in AppCompatActivity) of handling the Up button.
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
Run the app. The Up button should now work from the FlavorFragment, PickupFragment, and SummaryFragment. As you navigate to previous steps in the order flow, the fragments should show the right flavor and pickup date from the view model.
This is my android studio error

Why not working navigating back when I use optionsMenu to navigate a specific Fragment?

I use Navigatation component latest stable version.
I would like to create a shortcut option menu item in my application, which is navigates to a fragment.
This fragment is also used by the drawer menu.
So when I use the drawer menu for navigation, everything is good, but when I navigate to for example Fragment B and after that I use the options menu to navigate to Fragment C, and after the I can not navigate back to Fragment B from drawer, because it always shows Fragment C.
I can solve this problem by adding navController.popBackStack() before the navigation to Fragment C, but this is not good at all, becaouse the previous fragment is destroyed, and I can not go back to it, by pressing back button.
Is there any solution of this problem?
MainActivity
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main,menu)
menu?.findItem(R.id.action_worksheet_management)?.setOnMenuItemClickListener {
val navController = findNavController(R.id.nav_host_fragment_content_main)
navController.popBackStack()
navController.navigate(R.id.nav_work)
return#setOnMenuItemClickListener true
}
return true
}
private fun setUpNavigation() {
val navController = findNavController(R.id.nav_host_fragment_content_main)
setSupportActionBar(binding.appBarMain.toolbar)
val menuItems = mutableListOf(
R.id.nav_worksheet_browser,
R.id.nav_product,
R.id.nav_about,
R.id.nav_company_info,
R.id.nav_services,
R.id.nav_stock_receive,
R.id.nav_synchronization,
R.id.nav_order_return,
R.id.nav_work,
R.id.nav_settings,
R.id.nav_certificates
)
appBarConfiguration = AppBarConfiguration(
menuItems.toSet(),
binding.drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
binding.navView.setupWithNavController(navController)
}
override fun onBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_main)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
I resolved it, by changed the nav version from 2.4.1 to 2.3.5. I hope it will be fixed later.

Android Navigation Component - Setting HasOptionsMenu invalidates NavigateUp button

I'm using Android Navigation Component with a bottomNavigationView. I have configured the AppBar in my MainActivity so that a Navigate Up Button appears when the app is not on the start destination of the graph.
I have set SupportedActionBar and override onSupportNavigateUp like so:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.mainToolbar)
...
val controller = binding.bottomNavView.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.nav_host_container,
intent = intent
)
controller.observe(this, Observer { navController ->
appBarConfiguration = AppBarConfiguration(
topLevelDestinationIds = setOf(
navController.graph.startDestination,
R.id.navigation_level_up_onboarding
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
})
currentController = controller
}
override fun onSupportNavigateUp(): Boolean {
return currentController?.value?.navigateUp() ?: false
}
In the navigation graph I have a destination ProfileSettingsFragment which needs to have menu options. I have set them like so:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
....
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.profile_settings_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
}
Menu options are working fine, but, the navigateUp button stops working for this fragment as soon as I call setHasOptionsMenu(true).
What am I doing wrong? What is the proper way to add menu options on a fragment while keeping navigateUp behaviour when using Navigation Component?
Since you are using a Toolbar instead of
setupActionBarWithNavController(navController, appBarConfiguration)
you can use
toolbar.setupWithNavController(navController, appBarConfiguration)
and you do not need to override the onSupportNavigateUp() method.
This works fine with me. While using actionbar in onOptionsItemSelected() add this check for the up button being clicked/pressed.
In kotlin:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home->
requireActivity().onBackPressed()
....//rest of your code
}
while in java:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home :
getActivity().onBackPressed();
break;
....//rest of your code
}

Android onSupportNavigateUp when NavHost is not in MainActivity

I have an activity which holds FragmentContainerView. In the FragmentContainerView I have a NavHostFragment. I want to implement onSupportNavigateUp in the NavHostFragment.
class MenuNavHostFragment : Fragment() {
fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController,null)
}
}
in MainActivity.kt
private lateinit var menuNavHostFragment: MenuNavHostFragment
override fun onSupportNavigateUp(): Boolean {
return menuNavHostFragment.onSupportNavigateUp()
}
in fragment_menu_nav_host
...
tools:context=".View.MenuNavHostFragment">
<fragment
android:id="#+id/fragment_menu_nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
...
When I press the back button, my application destroys when I want it to go back one step in the navigation stack.
How do I solve this?
check Update UI components with NavigationUI
If you want go back, use findNavController.navigateUp() function
replace the mentioned code by the following one, according to your program:
open fun navigateUp (drawerLayout: DrawerLayout, navController: NavController):Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return navigateUp(this.drawerLayout, navController)
}

Navigate to specific fragment on BottomNavigationView

I've searched my problem but I could not find anything. let me describe my problem.
I have 3 buttons on BottomNavigationView (Home, User, History). then from other activity, I have a button which I want is going to User page (with BottomnavigationView of course.
I will show you my code. it still defaults all. I just do not know how to navigate to the User page.
MainActivity.kt
class MainActivity : AppCompatActivity() {
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_home, R.id.navigation_user, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}}
and here is my code (from other fragment)
otherFragment.kt
buttonRincian.setOnClickListener {
// i dont know command to go to MainActivity with User page as default selected menu
}
thank you so much, i hoe someone can help me.
Make an interface which your activity will implement.
All the fragments should call the method of the interface wherever you want to change the fragment.
something like
interface TabChangeListener {
fun onTabChange(tabName : String)
}
Code in Activity
class Activity : AppCompatActivity(), TabChangeListener {
override fun onTabChange(tabName : String) {
//code to show different tabs
}
}
Code in Fragments
class Frag1 : Fragment {
var listener : TabChangeListener
//somewhere in the code
listener.onTabChange("userTab")
}
Don't forget to take the reference of TabChangeListener in Fragments from the activity otherwise the callbacks won't work.

Categories

Resources