Antes de probar el componente de navegación, solía hacer transacciones de fragmentos manualmente y usé la etiqueta de fragmento para recuperar el fragmento actual.
val fragment:MyFragment = supportFragmentManager.findFragmentByTag(tag):MyFragment
Ahora en el diseño de mi actividad principal tengo algo como:
<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"
/>
¿Cómo puedo recuperar el fragmento mostrado actualmente por el componente de navegación? Haciendo
supportFragmentManager.findFragmentById(R.id.nav_host)
devuelve un NavHostFragment
y quiero recuperar mi 'MyFragment' mostrado.
Gracias.
onActivityResult
de mi actividad principal. Como no pude obtener el fragmento, simplemente moví todo esto al fragmento y parece funcionar.Respuestas:
Logré descubrir un camino por ahora y es el siguiente:
NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host); navHostFragment.getChildFragmentManager().getFragments().get(0);
En caso de que sepa que es el primer fragmento. Todavía estoy investigando una forma sin esto. Estoy de acuerdo en que no es la mejor manera, pero eso debería ser algo por ahora.
fuente
navHostFragment!!.childFragmentManager.fragments.any { it.javaClass == fragmentClass && it.isVisible }
funciona bastante similar. ¡Espero que ayude a cualquiera!No hay forma de que pueda encontrar para recuperar la instancia del fragmento actual. Sin embargo, puede obtener el ID del último fragmento agregado usando el código a continuación.
navController.currentDestination?.getId()
Devuelve el ID en el archivo de navegación. Espero que esto ayude.
fuente
Debe buscar la propiedad childFragmentManager primaryNavigationFragment de su fragmento de navegación, aquí es donde se hace referencia al fragmento que se muestra actualmente.
val navHost = supportFragmentManager.findFragmentById(R.id.main_nav_fragment) navHost?.let { navFragment -> navFragment.childFragmentManager.primaryNavigationFragment?.let {fragment-> //DO YOUR STUFF } } }
fuente
Esta parece la solución más limpia. Actualización: función de extensión cambiada a propiedad. Gracias Igor Wojda .
1. Crea la siguiente extensión
import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager val FragmentManager.currentNavigationFragment: Fragment? get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
2. En
Activity
laNavHostFragment
utilización de esta manera:val currentFragment = supportFragmentManager.currentNavigationFragment
fuente
FragmentManager.currentNavigationFragment
(no como una función)Usar
addOnDestinationChangedListener
en actividad teniendoNavHostFragment
Para 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()); } });
Para Kotlin
var navController :NavController=Navigation.findNavController(this, R.id.nav_host_fragment) navController.addOnDestinationChangedListener { controller, destination, arguments -> Log.e(TAG, "onDestinationChanged: "+destination.label); }
fuente
esto puede ser tarde, pero para cualquiera que todavía esté buscando
val currentFragment = NavHostFragment.findNavController(nav_host_fragment).currentDestination?.id
entonces puedes hacer algo como
if(currentFragment == R.id.myFragment){ //do something }
tenga en cuenta que esto es para kotlin, el código java debería ser casi el mismo
fuente
navController().currentDestination?.id
le dará su
Fragment
identificación actual dondeprivate fun navController() = Navigation.findNavController(this, R.id.navHostFragment)
esta identificación es la identificación que ha dado en su
Navigation Graph XML
archivo bajofragment
etiqueta. También puede compararcurrentDestination.label
si lo desea.fuente
Solución de trabajo encontrada.
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 } }
fuente
Desde una actividad que usa
NavHostFragment
, puede usar el siguiente código para recuperar la instancia deActive Fragment
.val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment
fuente
Mi requisito es obtener el fragmento visible actual de la actividad principal, mi solución es
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; }
Esto puede ayudar a alguien con el mismo problema.
fuente
Según @slhddn, responda y comente, así es como lo estoy usando y recuperando la identificación del fragmento del archivo 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) } } } }
fuente
¿Puede consultar con la
getChildFragmentManager()
llamada confuente
Hacer :
• en algún botón de tu fragmento:
val navController = findNavController(this) navController.popBackStack()
• En su actividad 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() }
fuente
Si necesita la instancia de su fragmento, puede ir con:
(Actividad) =>
supportFragmentManager.fragments.first().childFragmentManager.fragments.first()
Es muy feo, pero a partir de ahí puedes comprobar si es una instancia del fragmento con el que quieres jugar.
fuente
En Androidx, he probado muchos métodos para encontrar el fragmento requerido de
NavHostFragment
. Finalmente pude romperlo con el método siguientepublic 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; }
fuente
El primer fragmento en navhost fragment es el fragmento actual
Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment(); if (navHostFragment != null) {Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);}
fuente
Primero, obtienes el fragmento actual por id, luego puedes encontrar el fragmento, dependiendo de ese id.
int id = navController.getCurrentDestination().getId(); Fragment fragment = getSupportFragmentManager().findFragmentById(id);
fuente
Combiné respuesta Andrei Toaders y respuesta Mukul Bhardwajs con una
OnBackStackChangedListener
.Como atributo:
private FooFragment fragment;
En mi
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; } });
De esta manera puedo obtener un fragmento, que se mostrará más adelante. Incluso se puede realizar un bucle
frags
y comprobar varios fragmentos coninstanceof
.fuente
Necesito hacer esto para configurar una vista de navegación inferior y lo hice de esta manera:
val navController = Navigation.findNavController(requireActivity(), R.id.nav_tabs_home) val bottomNavBar: BottomNavigationView = nav_content_view NavigationUI.setupWithNavController(bottomNavBar, navController)
fuente
La mejor manera de lograr esto es registrar una devolución de llamada del ciclo de vida del fragmento .
Según la pregunta original, si tu
NavHostFragment
se define como ...<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" />
Luego, en tu actividad principal
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 } } )
Se pueden anular otros métodos de devolución de llamada para adaptarse a sus requisitos.
fuente
Esta solución funcionará en la mayoría de situaciones Pruebe esto:
val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment?.parentFragment as MainFragment
o esto:
val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment as MainFragment
fuente
Este código funciona conmigo
NavDestination current = NavHostFragment.findNavController(getSupportFragmentManager().getPrimaryNavigationFragment().getFragmentManager().getFragments().get(0)).getCurrentDestination(); switch (current.getId()) { case R.id.navigation_saved: // WRITE CODE break; }
fuente
Esto funciona para mi
(navController.currentDestination as FragmentNavigator.Destination).className
Regresará
canonicalName
de tu fragmentofuente
esto puede llegar tarde pero puede ayudar a alguien más tarde.
si está utilizando navegaciones anidadas, puede obtener una identificación como esta en Kotlin
val nav = Navigation.findNavController(requireActivity(), R.id.fragment_nav_host).currentDestination
y este es uno de los fragmentos en fragment_nav_host.xml
<fragment android:id="@+id/sampleFragment" android:name="com.app.sample.SampleFragment" android:label="SampleFragment" tools:layout="@layout/fragment_sample" />
y puedes comprobar todo lo que necesitas así
if (nav.id == R.id.sampleFragment || nav.label == "SampleFragment"){}
fuente
Finalmente, la solución de trabajo para aquellos de ustedes que todavía están buscando. En realidad, es muy simple y puede lograrlo usando la devolución de llamada.
sigue estos pasos:
Cree un oyente dentro del fragmento del que desea obtener la instancia de la actividad 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); } }
Implemente su oyente en el fragmento / actividad del host
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"); } } }
Y eso es todo lo que necesita para hacer el trabajo. Hop esto ayuda a alguien
fuente
La mejor manera que pude averiguar con 1 fragmento, Kotlin, uso de navegación:
En su archivo de diseño, agregue la etiqueta: "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" />
En tu actividad:
val navHostFragment = supportFragmentManager.findFragmentByTag("main_fragment_tag") as NavHostFragment val mainFragment = navHostFragment.childFragmentManager.fragments[0] as MainFragment mainFragment.mainFragmentMethod()
fuente
val fragment: YourFragment? = yourNavHost.findFragment()
Nota: la
findFragment
función de extensión se encuentra en elandroidx.fragment.app
paquete y es una función genéricafuente
En su actividad, defina un objeto de fragmento. Y desde cada fragmento, llame a este método pasando el objeto de fragmento, como Entonces, el objeto de fragmento estático será anulado por el fragmento actual que muestra cada vez.
//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>;
También puede configurar la devolución de llamada de un fragmento a una actividad, para un mejor enfoque y pasar su objeto de fragmento actual.
fuente