Im using Navigation Component which navigates between fragments using findNavController().navigate(). I want to retrieve the currently displayed fragment in FragmentContainerView from MainActivity as I want to modify the "Edit" button setOnClickListener function to perform "Save" function (I already know how to change the text from Edit to Save) where it checks currently displayed fragment and change the setOnClickListener function accordingly. So in that particular fragment, it will perform "Save" function. But how do I get the currently displayed fragment from MainActivity?
I saw alot other solution but they are all using FragmentTransaction or they just show the code which get the current Fragment but they didn't show in which part of MainActivity will initiate the code which gets the current Fragment. Any help? Im using Kotlin.
You could add a OnDestinationChangedListener to the NavController inside you MainActivity
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.id == R.id.your_savable_fragment) {
button.text = "Save"
//....
}
if(destination.id == R.id.your_editable_fragment) {
button.text = "Edit"
//....
}
}
Related
private fun navBottomClick() {
bottomNavigationView?.setOnItemSelectedListener {
when(it.itemId){
R.id.workout ->{
val fragmentTransaction:FragmentTransaction = supportFragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.container,WorkoutFragment(),"WORKOUT")
//fragmentTransaction.addToBackStack("WORKOUT")
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
fragmentTransaction.commit()
}
R.id.steps ->{
intent = Intent(this,StepsActivity::class.java)
startActivity(intent)
}
}
true
}
}
override fun onBackPressed() {
super.onBackPressed()
}
}
When I pressed back, my app is closed. I want to make it go from a fragment to the main acitvity.
You have misunderstood the concept of Fragments and Activity . The issue you facing of the application getting close on navigating back from the fragment because it is the last fragment present in the stack .
Concept :
Basically , an Activity acts as an container for all of your Fragments . So , you create an activity and create a Fragment-Container / FrameLayout in that Activity wherein you assign the Fragments. So , Consider this example :
Here you can see, there are two fragments and both of them are placed in only one Activity . So this clarifies that Activity acts as an container for fragments .
What causes the Issue of Application being closed :
So what happens is when you navigate back from the last fragment , since it does not have anywhere to go back it closes the application .
Solution :
So if you want to get your Activity on navigating back on the last fragment to the Activity then , you need to override the popBackStack() method on the last Fragment and in there you need to disable the FragmentContainer / FrameLayout view, in this way you can get your activity back .
Recommended Solution : Move all the stuffs that you want to show at the end from your Activity to another Fragment and popBackStack() to that Fragment, doing such maintains the Single Activity principle .
You should have a popbackstack to send the screen correctly. Check if your fragment has implemented inside of this activity, if yes, really that will be closed.
Don't forget that fragment is inside of the one activity.
You need to un-comment this line
//fragmentTransaction.addToBackStack("WORKOUT")
then it will work as there is no stack maintained activity can't go back to previous fragment and will close the activity.
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.
I am trying to pass data from dialog destination to fragment. But it is not getting called If I try the same consecutively. For single try it works fine.
Below is my code that is in my dialog fragment:
val navBackStackEntry = findNavController().getBackStackEntry(R.id.fragment_name)
onClick of button I am doing this
navBackStackEntry.savedStateHandle.set(ConstantUtils.SAVED_DATE, "")
dismiss()
In fragment's onResume I am observing the data like below:
val savedStateHandle = findNavController().currentBackStackEntry?.savedStateHandle
savedStateHandle?.getLiveData<String>(ConstantUtils.SAVED_DATE)?.observe(viewLifecycleOwner,
Observer { date ->
//Code goes here
savedStateHandle.remove<String>(ConstantUtils.SAVED_DATE)
})
When I click the button from dialog it comes to onResume of fragment, If I again go to the dialog and click on button it does not return to onResume of fragment.
Pleas let me know what mistake am I making here.
If you want to pass argument to fragment and receive one, you can use setFragmentResult() function can pass and receive bundle between fragments.
This is source link for more study
https://developer.android.com/guide/fragments/communicate#fragment-result
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()
}
}
I have multiple fragment, one bottom navigation view on bottom of Main Activity. The problem appears when I want to set selected item on Bottom Navigation View when fragment pop back from stack, setSelectedItemId always trigger OnBackStackChangedListener, thus make loop event. Here are the code
fragmentManager.addOnBackStackChangedListener {
var f : Fragment = fragmentManager.findFragmentById(R.id.frame)
if(f is HomeFragment){
bottomNavigation.selectedItemID = R.id.navigation_home
}
}
I've check from the documentation at developer.android.com and various post on StackOverflow or even forum and I don't find any proper solution for my case.
Any solution? thanks