Navigate to specific fragment on BottomNavigationView - android

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.

Related

(Android/Kotlin) Correct way to navigate to another fragment without using drawer [duplicate]

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.

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

how to perform an action instead of moving to another destination if I click a menu in Navigation Drawer using Navigation Component?

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
}
}

How to replace fragment inside another fragment in Kotlin?

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()
}
}

How to handle up button inside fragment using Navigation Components

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

Categories

Resources