Kotlin opening new fragment in nav drawer example - android

I'm relatively new with Kotlin and I'm trying to extend the navigation drawer example by adding a button into my fragment that can open another fragment directly without having to select it from the navigation drawer.
Here is my button listener in my fragment's onCreateView function:
addButton.setOnClickListener()
{
Toast.makeText(this.context,"ButtonPressed",Toast.LENGTH_SHORT).show()
this.activity.supportFragmentManager.beginTransaction().replace(R.id.mobile_navigation, R.layout.fragment2).commit()
}
I'm not sure I completely understand how to approach this. The button works fine and calls the toast, but I can't get it to change the fragment.
Any help would be appreciated.

the template has a mobile_navigation.xml file with a "navigation" element.
The Navigation Architecture components is used by default in recent android studio versions, so the navController is the responsible for fragment transaction instead of doing that manually by the supportFragmentManager
addButton.setOnClickListener() {
Toast.makeText(this.context,"ButtonPressed",Toast.LENGTH_SHORT).show()
val navHostFragment = requireActivity().supportFragmentManager
.primaryNavigationFragment as NavHostFragment
navHostFragment.navController.navigate(R.layout.fragment2)
}
Also, make sure that R.layout.fragment2 is the fragment id of the destination fragment in the R.id.mobile_navigation.xml

Related

Navigation Component how to make each fragment only has one instance all the time

My project
Single activity pattern with fragments in kotlin.
Navigation component + bottom navigation view together.
There are four tabs(fragments) in bottom navigation view.
My issue is changing each tab in bottom navigation, then each fragment is re-created which due to the app is laggy.
So my target is making only one instance of each fragment there.
What I tried is:
adding app:launchSingleTop="true" for the tab fragment in grap.xml. DOESN'T WORK.
This idea is if the tab fragment can be pop backed then use it directly or create new. But this only works sometimes. Some times the tab fragment does not re-created but some times are!
I think the reason is pop back stack clear it for some time? Not sure.
binding.bottomNavigationView.setOnItemSelectedListener { item: MenuItem ->
if (!navController.popBackStack(item.itemId, false)) {
NavigationUI.onNavDestinationSelected(item , navController)
}
true
}
I used navController.navigate(item.itemId, null, NavOptions.Builder().setPopUpTo(item.itemId, false).build()) to replace NavigationUI.onNavDestinationSelected(item , navController), still doesn't work.
Any idea? thanks!
just add this piece of code to avoid recreation
binding.bottomNavigationView.setOnItemReselectedListener { }

Call different Fragment function in Activity in Android

The code is in the Android Studio template.
Android Studio - Create new project - Navigation Drawer Activity
There are an Activity and three Fragments (HomeFragment, GalleryFragment, SlideshowFragment) in the template project. I use an AppBarConfiguration object to manage three Fragment. Now I create a function in each Fragment.
My title may be a bit vague. My problem is how to execute the method in the current fragment by clicking the button in Activity.
Now my solution is as follows.
In each fragment. Get the activity object and find the button. Then set the click method. Here is my Kotlin code.
activity?.findViewById<FloatingActionButton>(R.id.fab)?.setOnClickListener { view ->
myFunction()
}
It works fine. But I think this is not elegant enough. And there are some problems with this. If I only set the click event of one fragment, when I switch to another fragment, the click event just now will be executed after I click the button.
I guess the reason for the above problem is that the click event of the activity is bound by the fragment.
My other solution is as follows.
Create an ActivityViewModel and set a LiveData value. Change value after clicking the button. Get ActivityViewModel in fragment and observe the value in each fragment. Then execute the method when the value is changed
My third solution is as follows.
Get each fragment object and determine whether it is visible. Then perform the function of the visible fragment. Here is my Kotlin code.
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
var fragment1 = navHostFragment!!.childFragmentManager.fragments[0] as HomeFragment
var fragment2 = navHostFragment!!.childFragmentManager.fragments[1] as GalleryFragment
var fragment3 = navHostFragment!!.childFragmentManager.fragments[2] as SlideshowFragment
if(fragment1.isVisiable){
fragment1.myFunction()
}else if(fragment2.isVisiable){
fragment2.myFunction()
}else if(fragment3.isVisiable){
fragment3.myFunction()
}
But I still think the methods above are not elegant enough.
Can I use the interface to achieve the above functions? And how to achieve it?
I am not a native English speaker. Sorry for my bad English.
Thanks.

Navigation Controller (Managing Backstack) Jetpack Android

Good day. So I've been working around with NavComponent of Jetpack for Android
I've thought that management of BackStack of fragments had to be implemented there already, well in fact it is there but I have faced an issue.
Here is my structure:
I have and entry Activity
I have a NavHost in the activity
I have Bottom Navigation bar in the Activity
For each Bottom Item I am using separate Fragments to navigate through.
Here is the code for the navigation.
bottomNavigationView.setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.navigation_home -> {
navController.apply {
navigate(R.id.navigation_home)
}
true
}
R.id.navigation_dashboard -> {
navController.apply {
navigate(R.id.dashboardFragment)
}
true
}
R.id.navigation_notifications -> {
true
}
else -> {
false
}
}
}
Never mind the last item.
So the issue is next.
If I try to switch between home and dashboard multiple times, when I press back then the stack surely will start popping all the items included there. So if I move like 6 times it will take me 12 attempts to actually exit the app.
Currently I couldn't find any source where for example the navigate() method will accept some sort of argument to cash my fragments instead of recreating it each time and adding to the BackStack.
So what kind of approach would you suggest?
If I to manage the BackStack manually on each back button pressed, what's the purpose of NavController at all? Just for creating and FORWARD navigation?
I think I'm missing some source in Android's official docs.
Thank you beforehand.
P.S.
using navController.popBackStack() before calling navigate() surely isn't the correct choice.
According to the documentation here :
NavigationUI can also handle bottom navigation. When a user selects a menu item, the NavController calls onNavDestinationSelected() and automatically updates the selected item in the bottom navigation bar.
to do so you have to give your bottom navigation items an ids as same as the corresponding destination in your navigation graph , and then tie you bottom view to the controller like this :
NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
NavController navController = navHostFragment.getNavController();
BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
NavigationUI.setupWithNavController(bottomNav, navController);
Note : from my personal experience , when the startDestination in the graph , that start by default is not currently in back stack (In my case it was the landing page which i pop it out when going to home fragment) then the app act with weird behavior like this . so make sure the start destination is existed in your back stack on should work fine .

how to go back to previous destination from fragment two to fragment one on button click in Jetpack Navigation

I am using Jetpack navigation to navigate between the fragments.Since I am using it for the first time I am unaware about how it will navigate from fragment two to fragment one on click of a button or based on some condition in the application.Please let me know if anyone knows about it
Try these codes:
yourButton.setOnClickListener(){
activity?.onNavigateUp()
}
or
val activity = requireActivity()
yourButton.setOnClickListener(){
if (activity is YourMainActivity) {
activity.onSupportNavigateUp()
//or
activity.onBackPressed()
}
}

findNavController and isolated fragment

I launch a BottomSheetDialogFragment from the main fragment with the show function (navigation component can't start DialogFragments).
Now in the BottomSheetDialogFragment I have a button to move to a detail activity.
I have the BottomSheetDialogFragment defined in the graph (isolated) and it points to the detail activity.
But when I try to navigate, it can't find the navController. Is it possible to pass the navController to this isolated fragment?
MainFragment to Detail is working
DialogFragment to Detail is not working.
I tried:
- findNavController: navigation is not set
- activity.findNavController(...)
But when I try to navigate, it can't find the navController. That's how navigation-component work.
Is it possible to pass the navController to this isolated fragment? I hope you will not going with that, replacing navController is not the perfect solution for your case.
What to do?
You can have new nav.xml with new parent activity and the (isolated) fragment as child, and navigate from the BottomSheetDialogFragment to (isolated) fragment-activity.
Otherwise, I don't see any problems that prevent you from adding related fragments in one nav.xml.
Also you may need to obey for navigation-component contract, don't use show() function while using navigation-component, you may miss some advantages here!
You really don't need show function see:-
Android Activity as a dialog
Explanation:-
You can have a parent activity and set it's theme as Dialog, so all fragments (inside the nav.xml) will be dialogs..
I used this trick in one of my apps before.

Categories

Resources