Перед тем, как попробовать компонент 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"
/>
Как я могу получить текущий отображаемый фрагмент с помощью компонента навигации? Делать
supportFragmentManager.findFragmentById(R.id.nav_host)
возвращает a, NavHostFragment
и я хочу получить показанный мной MyFragment.
Спасибо.
onActivityResult
своей основной деятельности. Так как получить фрагмент не удалось, я просто переместил все это в сам фрагмент и вроде работает.Ответы:
На данный момент мне удалось найти способ, и он выглядит следующим образом:
NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host); navHostFragment.getChildFragmentManager().getFragments().get(0);
Если вы, конечно, знаете, что это первый фрагмент. Я все еще ищу способ без этого. Я согласен, что это не лучший способ, но на данный момент это должно быть что-то важное.
источник
navHostFragment!!.childFragmentManager.fragments.any { it.javaClass == fragmentClass && it.isVisible }
работает очень похоже. Надеюсь, это кому-нибудь поможет!Я не могу найти способ получить текущий экземпляр фрагмента. Однако вы можете получить идентификатор последнего добавленного фрагмента, используя приведенный ниже код.
navController.currentDestination?.getId()
Он возвращает идентификатор в файле навигации. Надеюсь это поможет.
источник
Вы должны посмотреть свойство childFragmentManager primaryNavigationFragment вашего навигационного фрагмента, именно здесь есть ссылка на текущий отображаемый фрагмент.
val navHost = supportFragmentManager.findFragmentById(R.id.main_nav_fragment) navHost?.let { navFragment -> navFragment.childFragmentManager.primaryNavigationFragment?.let {fragment-> //DO YOUR STUFF } } }
источник
Это кажется самым чистым решением. Обновление: изменена функция расширения на свойство. Спасибо Игорю Войде .
1. Создайте следующее расширение
import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager val FragmentManager.currentNavigationFragment: Fragment? get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
2.
Activity
сNavHostFragment
использованием его как это:val currentFragment = supportFragmentManager.currentNavigationFragment
источник
FragmentManager.currentNavigationFragment
(а не как функцию)Использование
addOnDestinationChangedListener
в деятельности, имеющейNavHostFragment
Для Java
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()); } });
Для Котлина
var navController :NavController=Navigation.findNavController(this, R.id.nav_host_fragment) navController.addOnDestinationChangedListener { controller, destination, arguments -> Log.e(TAG, "onDestinationChanged: "+destination.label); }
источник
это может быть поздно, но для тех, кто все еще ищет
val currentFragment = NavHostFragment.findNavController(nav_host_fragment).currentDestination?.id
тогда вы можете сделать что-то вроде
if(currentFragment == R.id.myFragment){ //do something }
обратите внимание, что это для котлина, Java-код должен быть почти таким же
источник
navController().currentDestination?.id
даст вам текущий
Fragment
идентификатор, гдеprivate fun navController() = Navigation.findNavController(this, R.id.navHostFragment)
этот идентификатор - это идентификатор, который вы указали в своем
Navigation Graph XML
файле подfragment
тегом. Вы также можете сравнить,currentDestination.label
если хотите.источник
Нашел рабочее решение.
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 } }
источник
Из Activity, который использует
NavHostFragment
, вы можете использовать приведенный ниже код для получения экземпляраActive Fragment
.val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment
источник
Мое требование - получить текущий видимый фрагмент из родительской активности, мое решение
private LoginFragment getCurrentVisibleFragment() { NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager().getPrimaryNavigationFragment(); FragmentManager fragmentManager = navHostFragment.getChildFragmentManager(); Fragment loginFragment = fragmentManager.getPrimaryNavigationFragment(); if(loginFragment instanceof LoginFragment){ return (LoginFragment)loginFragment; } return null; }
Это может помочь кому-то с той же проблемой.
источник
В соответствии с ответом и комментарием @slhddn вот как я его использую и получаю идентификатор фрагмента из файла nav_graph.xml :
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(findViewById(R.id.toolbar)) val navController = findNavController(this, R.id.nav_host_fragment) ivSettingsCog.setOnClickListener { if (navController.currentDestination?.id == R.id.updatesFragment) // Id as per set up on nav_graph.xml file { navController.navigate(R.id.action_updatesFragment_to_settingsFragment) } } } }
источник
Можете ли вы уточнить,
getChildFragmentManager()
позвонив по телефонуисточник
Сделать :
• в какой-то кнопке в вашем фрагменте:
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() }
источник
Если вам нужен экземпляр вашего фрагмента, вы можете использовать:
(Активность) =>
supportFragmentManager.fragments.first().childFragmentManager.fragments.first()
Это очень уродливо, но оттуда вы можете проверить, является ли это экземпляром фрагмента, с которым вы хотите поиграть
источник
На Androidx я перепробовал множество способов найти нужный фрагмент из файлов
NavHostFragment
. Наконец, я смог взломать его с помощью метода ниже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; }
источник
Первый фрагмент во фрагменте navhost - это текущий фрагмент
Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment(); if (navHostFragment != null) {Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);}
источник
Сначала вы получаете текущий фрагмент по идентификатору, затем вы можете найти фрагмент в зависимости от этого идентификатора.
int id = navController.getCurrentDestination().getId(); Fragment fragment = getSupportFragmentManager().findFragmentById(id);
источник
Я объединил Андрей Toaders ответ и Mukul Bhardwajs ответ с
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
.источник
Мне нужно сделать это, чтобы настроить нижний вид навигации, и я сделал это следующим образом:
val navController = Navigation.findNavController(requireActivity(), R.id.nav_tabs_home) val bottomNavBar: BottomNavigationView = nav_content_view NavigationUI.setupWithNavController(bottomNavBar, navController)
источник
Лучший способ добиться этого - зарегистрировать обратный вызов жизненного цикла фрагмента .
Согласно исходному вопросу, если ваш
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 } } )
Другие методы обратного вызова могут быть переопределены в соответствии с вашими требованиями.
источник
Это решение будет работать в большинстве ситуаций. Попробуйте следующее:
val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment?.parentFragment as MainFragment
или это:
val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment as MainFragment
источник
Этот код работает у меня
NavDestination current = NavHostFragment.findNavController(getSupportFragmentManager().getPrimaryNavigationFragment().getFragmentManager().getFragments().get(0)).getCurrentDestination(); switch (current.getId()) { case R.id.navigation_saved: // WRITE CODE break; }
источник
Это работает для меня
(navController.currentDestination as FragmentNavigator.Destination).className
Он вернет
canonicalName
ваш фрагментисточник
это может быть поздно, но может помочь кому-то позже.
если вы используете вложенную навигацию, вы можете получить такой идентификатор в Kotlin
val nav = Navigation.findNavController(requireActivity(), R.id.fragment_nav_host).currentDestination
и это один из фрагментов в fragment_nav_host.xml
<fragment android:id="@+id/sampleFragment" android:name="com.app.sample.SampleFragment" android:label="SampleFragment" tools:layout="@layout/fragment_sample" />
и вы можете проверить все, что вам нужно, вот так
if (nav.id == R.id.sampleFragment || nav.label == "SampleFragment"){}
источник
Наконец, рабочее решение для тех из вас, кто все еще ищет. На самом деле это очень просто, и вы можете добиться этого с помощью обратного вызова.
Следуй этим шагам:
Создайте слушателя внутри фрагмента, который вы хотите получить экземпляр из активности onCreate ()
public class HomeFragment extends Fragment { private OnCreateFragment createLIstener; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { createLIstener.onFragmentCreated(this); View root = inflater.inflate(R.layout.fragment_home, container, false); //findViews(root); return root; } @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_main, menu); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { if (item.getItemId()==R.id.action_show_filter){ //do something } return super.onOptionsItemSelected(item); } @Override public void onAttach(Context context) { super.onAttach(context); try { createLIstener = (OnCreateFragment) context; } catch (ClassCastException e) { throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener"); } } public interface OnCreateFragment{ void onFragmentCreated(Fragment f); } }
Реализуйте свой слушатель в хосте Fragment / Activity
public class MainActivity extends AppCompatActivity implements HomeFragment.OnCreateFragment { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); BottomNavigationView navView = findViewById(R.id.nav_view); // Passing each menu ID as a set of Ids because each // menu should be considered as top level destinations. AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder( R.id.navigation_home, R. ----) .build(); NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration); NavigationUI.setupWithNavController(navView, navController); } @Override public void onFragmentCreated(Fragment f) { if (f!=null){ H.debug("fragment created listener: "+f.getId()); f.setHasOptionsMenu(true); }else { H.debug("fragment created listener: NULL"); } } }
И это все, что вам нужно для работы. Хоп это помочь кому-то
источник
Лучший способ, которым я мог разобраться с использованием 1 фрагмента, Kotlin, Navigation:
В файл макета добавьте тег: "android: tag =" main_fragment_tag ""
<fragment android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/nav_host" app:navGraph= "@navigation/nav_item" android:tag="main_fragment_tag" android:name="androidx.navigation.fragment.NavHostFragment" app:defaultNavHost= "true" />
О вашей деятельности:
val navHostFragment = supportFragmentManager.findFragmentByTag("main_fragment_tag") as NavHostFragment val mainFragment = navHostFragment.childFragmentManager.fragments[0] as MainFragment mainFragment.mainFragmentMethod()
источник
val fragment: YourFragment? = yourNavHost.findFragment()
Примечание:
findFragment
функция расширения находится вandroidx.fragment.app
пакете, и это общая функцияисточник
В своей деятельности определите объект-фрагмент. И из каждого фрагмента вызовите этот метод, передав объект фрагмента, например, объект статического фрагмента будет заменен текущим отображаемым фрагментом каждый раз.
//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>;
Вы также можете установить обратный вызов от фрагмента к действию для лучшего подхода и передать текущий объект фрагмента.
источник