Android Navigation Architecture Component - Get current visible fragment

[亡魂溺海] 提交于 2019-12-02 21:39:47

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.

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.

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

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

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

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

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()
Shiam Shabbir Himel

can you please check with getChildFragmentManager() call with

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

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.

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.

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)

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

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.

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

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

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