Android Navigation Architecture Component - Get current visible fragment

假装没事ソ 提交于 2019-12-03 08:06:10

问题


Before trying the Navigation component I used to manually do fragment transactions and used the fragment tag in order to fetch the current fragment.

val fragment:MyFragment = supportFragmentManager.findFragmentByTag(tag):MyFragment

Now in my main activity layout I have something like:

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

How can I retrieve the current displayed fragment by the Navigation component? Doing

supportFragmentManager.findFragmentById(R.id.nav_host)

returns a NavHostFragment and I want to retrieve my shown 'MyFragment`.

Thank you.


回答1:


I managed to discover a way for now and it is as follows:

NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host);
navHostFragment.getChildFragmentManager().getFragments().get(0);

In case of course you know it is the first fragment. I am still investigating a way without this. I agree it is not the best way but that should be something for now.




回答2:


There is no way I can find to retrieve the current fragment instance. However, you can get the ID of lastly added fragment using the code below.

navController.getCurrentDestination().getId()

It returns the ID in navigation file. Hope this helps.




回答3:


You should look the childFragmentManager primaryNavigationFragment property of your nav fragment, this is where the current displayed fragment is referenced.

val navHost = supportFragmentManager.findFragmentById(R.id.main_nav_fragment)
    navHost?.let { navFragment ->
        navFragment.childFragmentManager.primaryNavigationFragment?.let {fragment->
                //DO YOUR STUFF
        }
    }
}



回答4:


Use addOnDestinationChangedListener in activity having NavHostFragment

 NavController navController= Navigation.findNavController(MainActivity.this,R.id.your_nav_host);

        navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
                Log.e(TAG, "onDestinationChanged: "+destination.getLabel());
            }
        });



回答5:


this might be late but for anyone who's still looking

val currentfraagment=NavHostFragment.findNavController(nav_host_fragment).currentDestination!!.id

then you can do something like

if(currentfraagment == R.id.myFragemnt){
     //do something
}

note that this is for kotlin, java code should be almost the same




回答6:


This seems like the cleanest solution.

1. Create the following extension

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager

fun FragmentManager.getCurrentNavigationFragment(): Fragment? =
    primaryNavigationFragment?.childFragmentManager?.fragments?.first()

2. In Activity with NavHostFragment use it like this:

val currentFragment = supportFragmentManager.getCurrentNavigationFragment()



回答7:


Found working solution.

private fun getCurrentFragment(): Fragment? {
    val currentNavHost = supportFragmentManager.findFragmentById(R.id.nav_host_id)
    val currentFragmentClassName = ((this as NavHost).navController.currentDestination as FragmentNavigator.Destination).className
    return currentNavHost?.childFragmentManager?.fragments?.filterNotNull()?.find {
        it.javaClass.name == currentFragmentClassName
    }
}



回答8:


can you please check with getChildFragmentManager() call with

NavHostFragment fragment = supportFragmentManager.findFragmentById(R.id.nav_host);
MyFragment frag = (MyFragment) fragment.getChildFragmentManager().findFragmentByTag(tag);



回答9:


If you need the instance of your fragment, you can go with:

(Activity) => supportFragmentManager.fragments.first().childFragmentManager.fragments.first()

It's very ugly but from there you can check if it's an instance of the fragment you want to play around with




回答10:


In your activity define a fragment object. And from each fragment call this method by passing fragment object, like So the static fragment object will be overridden by current showing fragment every time.

//method in MainActivity
private static Fragment fragment;

public void setFragment(Fragment fragment){
this.fragment = fragment;
}

//And from your fragment class, you can call
((<yourActivity in which fragment present>)getActivity()).setFragment(<your fragment object>);

//if you want to set it directly;
 ((<yourActivity in which fragment present>)getActivity()).fragment=<your fragment object>;

You can also set callback from fragment to activity, for a better approach and pass your current fragment object.




回答11:


I combined Andrei Toaders answer and Mukul Bhardwajs answer with an OnBackStackChangedListener.

As an attribute:

private FooFragment fragment;

In my onCreate

NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host);
FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();
FragmentManager.OnBackStackChangedListener listener = () -> {
        List<Fragment> frags = navHostManager.getFragments();
        if(!frags.isEmpty()) {
            fragment = (FooFragment) frags.get(0);
        }
};
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
        if(destination.getId()==R.id.FooFragment){
            navHostManager.addOnBackStackChangedListener(listener);
        } else {
            navHostManager.removeOnBackStackChangedListener(listener);
           fragment = null;
        }
});

This way i can get a fragment, which will be displayed later on. One even may be able to loop though frags and check multiple fragments with instanceof.




回答12:


I need to do this to setup a bottom navigation view and I did it this way:

val navController = Navigation.findNavController(requireActivity(), R.id.nav_tabs_home)
        val bottomNavBar: BottomNavigationView = nav_content_view
        NavigationUI.setupWithNavController(bottomNavBar, navController)



回答13:


First, you get the current fragment by id, then you can find the fragment, depending on that id.

int id = navController.getCurrentDestination().getId();
Fragment fragment = getSupportFragmentManager().findFragmentById(id)l



回答14:


The best way to achieve this is to register a fragment lifecycle callback.

As per the original question, if your NavHostFragment is defined as...

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

Then in your main activity onCreate(..)...

nav_host.childFragmentManager.registerFragmentLifecycleCallbacks(
    object:FragmentManager.FragmentLifecycleCallbacks() {
        override fun onFragmentViewCreated(
            fm: FragmentManager, f: Fragment, v: View,
            savedInstanceState: Bundle?
        ) {
            // callback method always called whenever a
            // fragment is added, or, a back-press returns
            // to the start-destination
        }
    }
)

Other callback methods may be overridden to fit your requirements.




回答15:


Make :

• in some button in your fragment:

val navController = findNavController(this)
  navController.popBackStack()

• In your Activity onBackPressed()

override fun onBackPressed() {
        val navController = findNavController(R.id.nav_host_fragment)
        val id = navController.currentDestination?.getId()
        if (id == R.id.detailMovieFragment){
            navController.popBackStack()
            return
        }

        super.onBackPressed()
    } 



回答16:


On Androidx, I have tried many methods for finding out required fragment from NavHostFragment. Finally I could crack it with below method

public Fragment getFunctionalFragment (String tag_name)
{
    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
    FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();

    Fragment fragment=null;
    List fragment_list = navHostManager.getFragments();

    for (int i=0; i < fragment_list.size() ; i ++ )
    {
        if ( fragment_list.get(i) instanceof HomeFragment && tag_name.equals("frg_home")) {
            fragment = (HomeFragment) fragment_list.get(i);
            break;
        }
    }

    return fragment;
}



回答17:


navController().currentDestination?.id

will give you your current Fragment's id where

private fun navController() = Navigation.findNavController(this, R.id.navHostFragment)

this id is the id which you have given in your Navigation Graph XML file under fragment tag. You could also compare currentDestination.label if you want.



来源:https://stackoverflow.com/questions/51385067/android-navigation-architecture-component-get-current-visible-fragment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!