Estou tentando usar o novo componente de navegação. Eu uso um BottomNavigationView com o navController: NavigationUI.setupWithNavController (bottomNavigation, navController)
Mas quando estou trocando fragmentos, eles são destruídos / criados a cada vez, mesmo que tenham sido usados anteriormente.
Existe uma maneira de manter vivo nosso link de fragmentos principais para nosso BottomNavigationView?
android
navigation
bottomnavigationview
IdAndro
fonte
fonte
Respostas:
Experimente isso.
Navegador
Crie um navegador personalizado.
@Navigator.Name("custom_fragment") // Use as custom tag at navigation.xml class CustomNavigator( private val context: Context, private val manager: FragmentManager, private val containerId: Int ) : FragmentNavigator(context, manager, containerId) { override fun navigate(destination: Destination, args: Bundle?, navOptions: NavOptions?) { val tag = destination.id.toString() val transaction = manager.beginTransaction() val currentFragment = manager.primaryNavigationFragment if (currentFragment != null) { transaction.detach(currentFragment) } var fragment = manager.findFragmentByTag(tag) if (fragment == null) { fragment = destination.createFragment(args) transaction.add(containerId, fragment, tag) } else { transaction.attach(fragment) } transaction.setPrimaryNavigationFragment(fragment) transaction.setReorderingAllowed(true) transaction.commit() dispatchOnNavigatorNavigated(destination.id, BACK_STACK_DESTINATION_ADDED) } }
NavHostFragment
Crie NavHostFragment personalizado.
class CustomNavHostFragment: NavHostFragment() { override fun onCreateNavController(navController: NavController) { super.onCreateNavController(navController) navController.navigatorProvider += PersistentNavigator(context!!, childFragmentManager, id) } }
Navigation.xml
Use a tag personalizada em vez da tag do fragmento.
<navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/navigation" app:startDestination="@id/navigation_first"> <custom_fragment android:id="@+id/navigation_first" android:name="com.example.sample.FirstFragment" android:label="FirstFragment" /> <custom_fragment android:id="@+id/navigation_second" android:name="com.example.sample.SecondFragment" android:label="SecondFragment" /> </navigation>
layout de atividade
Use CustomNavHostFragment em vez de NavHostFragment.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/nav_host_fragment" android:name="com.example.sample.CustomNavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@+id/bottom_navigation" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/navigation" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_navigation" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:menu="@menu/navigation" /> </androidx.constraintlayout.widget.ConstraintLayout>
Atualizar
Criei um projeto de amostra. ligação
Não crio NavHostFragment personalizado. Eu uso
navController.navigatorProvider += navigator
.fonte
fragments
são reutilizados, não recriados), há um problema com a navegação. Cadamenuitem
nosbottomnavigationview
é considerado primário - assim, quandoBACK
é pressionado, os acabamentos aplicativo (ou vai para o componente superior). Uma solução melhor seria se comportar exatamente como o aplicativo do YouTube: (1) Toque em Início; (2) Tendência de toque; (3) Toque em Caixa de entrada; (4) Tendência de toque; (5) Toque emBACK
- vai para a caixa de entrada; (6) TapBACK
- vai para a página inicial; (7) TapBACK
- o aplicativo existe. Em resumo, aBACK
funcionalidade do YouTube entre "menuitems
" volta aos mais recentes, sem itens repetidos.app:navGraph
do NavHostFragment de sua atividade.Link de amostras do Google Basta copiar NavigationExtensions para seu aplicativo e configurar por exemplo. Funciona bem.
fonte
Depois de muitas horas de pesquisa, encontrei a solução. Estava o tempo todo bem na nossa frente :) Existe uma função:
popBackStack(destination, inclusive)
navegar para um determinado destino se encontrado no backStack. Ele retorna booleano, para que possamos navegar até lá manualmente se o controlador não encontrar o fragmento.if(findNavController().popBackStack(R.id.settingsFragment, false)) { Log.d(TAG, "SettingsFragment found in backStack") } else { Log.d(TAG, "SettingsFragment not found in backStack, navigate manually") findNavController().navigate(R.id.settingsFragment) }
fonte
Se você tiver problemas para passar argumentos, adicione:
fragment.arguments = args
em aula
KeepStateNavigator
fonte
Não disponível a partir de agora.
Como uma solução alternativa, você pode armazenar todos os seus dados buscados no modelo de exibição e ter esses dados prontamente disponíveis ao recriar o fragmento. Certifique-se de obter a visualização usando o contexto de atividades.
Você pode usar o LiveData para tornar seu ciclo de vida de dados observável
fonte
Usei o link fornecido por @STAR_ZERO e funciona bem. Para aqueles que estão tendo problemas com o botão Voltar, você pode manipulá-lo no host activity / nav desta forma.
override fun onBackPressed() { if(navController.currentDestination!!.id!=R.id.homeFragment){ navController.navigate(R.id.homeFragment) }else{ super.onBackPressed() } }
Basta verificar se o destino atual é o seu fragmento raiz / home (normalmente o primeiro na visualização de navegação inferior), se não, navegue de volta para o fragmento, se sim, apenas saia do aplicativo ou faça o que quiser.
A propósito, esta solução precisa funcionar em conjunto com o link de solução acima fornecido por STAR_ZERO, usando keep_state_fragment .
fonte
A solução fornecida por @ piotr-prus me ajudou, mas eu tive que adicionar alguma verificação de destino atual:
if (navController.currentDestination?.id == resId) { return //do not navigate }
sem esta verificação, o destino atual será recriado se você navegar por engano até ele, porque não seria encontrado na pilha de retorno.
fonte
De acordo com a documentação do Android ,
Mude seu nav_host_fragment para -> FragmentContainerView e recupere o navController
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController
Você pode preservar o estado do fragmento com Componentes de Navegação usando esta abordagem
fonte