Компонент архитектуры Android Navigation - получить текущий видимый фрагмент

Перед попыткой компонента Navigation я использовал для ручного выполнения транзакций фрагментов и использовал тег фрагмента для извлечения текущего фрагмента.

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

Теперь в моем основном макете деятельности у меня есть что-то вроде:

<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"
        />

Как я могу получить текущий отображаемый фрагмент компонентом Navigation? дела

supportFragmentManager.findFragmentById(R.id.nav_host)

возвращает NavHostFragment и я хочу получить показанный "MyFragment".

Спасибо.

Ответы

Ответ 1

Мне удалось найти способ на данный момент, и он выглядит следующим образом:

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

В случае, конечно, вы знаете, что это первый фрагмент. Я все еще изучаю путь без этого. Я согласен, что это не лучший способ, но на данный момент это должно быть что-то.

Ответ 2

Я не могу найти, чтобы извлечь текущий экземпляр фрагмента. Однако вы можете получить идентификатор последнего добавленного фрагмента, используя следующий код.

navController.getCurrentDestination().getId()

Он возвращает идентификатор в файле навигации. Надеюсь это поможет.

Ответ 3

Вы должны смотреть свойство childFragmentManager primaryNavigationFragment вашего навигационного фрагмента, здесь находится ссылка на текущий отображаемый фрагмент.

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

Ответ 4

это может быть поздно, но для тех, кто все еще ищет

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

тогда вы можете сделать что-то вроде

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

обратите внимание, что это для kotlin, код Java должен быть почти таким же

Ответ 5

Нашел рабочее решение.

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

Ответ 6

Используйте addOnDestinationChangedListener в деятельности, имеющей 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());
            }
        });

Ответ 7

вы можете проверить с помощью вызова getChildFragmentManager() с

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

Ответ 8

Это кажется самым чистым решением.

1. Создайте следующее расширение

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

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

2. В Activity с NavHostFragment используйте это так:

val currentFragment = supportFragmentManager.getCurrentNavigationFragment()

Ответ 9

В вашей деятельности определите объект фрагмента. И из каждого фрагмента вызывается этот метод, передавая объект фрагмента, например So, поэтому объект статического фрагмента будет переопределен текущим отображающим фрагментом каждый раз.

//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>;

Вы также можете установить обратный вызов из фрагмента в действие, для лучшего подхода и передачи вашего текущего объекта фрагмента.

Ответ 10

Я объединил ответ Андрея Тоадера и Мукула OnBackStackChangedListener с OnBackStackChangedListener.

В качестве атрибута:

private FooFragment fragment;

В моем 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;
        }
});

Таким образом, я могу получить фрагмент, который будет отображаться позже. Можно даже frags фрагменты и проверить несколько фрагментов с помощью instanceof.

Ответ 11

Мне нужно сделать это, чтобы настроить вид нижней навигации, и я сделал это следующим образом:

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

Ответ 12

Сначала вы получаете текущий фрагмент по идентификатору, затем вы можете найти фрагмент в зависимости от этого идентификатора.

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

Ответ 13

Лучший способ добиться этого - зарегистрировать обратный вызов жизненного цикла фрагмента.

Согласно первоначальному вопросу, если ваш NavHostFragment определен как...

<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"
        />

Тогда в своей основной деятельности 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
        }
    }
)

Другие методы обратного вызова могут быть переопределены в соответствии с вашими требованиями.

Ответ 14

Сделать:

• в какой-то кнопке в вашем фрагменте:

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

• В вашей активности 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()
    } 

Ответ 15

Если вам нужен экземпляр вашего фрагмента, вы можете использовать:

(Деятельность) => supportFragmentManager.fragments.first().childFragmentManager.fragments.first()

Это очень уродливо, но оттуда вы можете проверить, является ли это фрагмент фрагмента, с которым вы хотите поиграть

Ответ 16

Чтобы получить текущий фрагмент, вы можете вызвать метод getPrimaryNavigationFragment()

Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host)
    .getChildFragmentManager().getPrimaryNavigationFragment();