新しいナビゲーションコンポーネントを使用しようとしています。 BottomNavigationViewをnavControllerで使用します:NavigationUI.setupWithNavController(bottomNavigation、navController)
しかし、フラグメントを切り替えると、以前に使用されていたとしても、そのたびに破棄/作成されます。
BottomNavigationViewへのメインフラグメントリンクを維持する方法はありますか?
これを試して。
カスタムナビゲーターを作成します。
@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を作成します。
class CustomNavHostFragment: NavHostFragment() {
override fun onCreateNavController(navController: NavController) {
super.onCreateNavController(navController)
navController.navigatorProvider += PersistentNavigator(context!!, childFragmentManager, id)
}
}
フラグメントタグの代わりにカスタムタグを使用します。
<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>
NavHostFragmentの代わりにCustomNavHostFragmentを使用します。
<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>
サンプルプロジェクトを作成しました。 リンク
カスタムNavHostFragmentを作成しません。 navController.navigatorProvider += navigator
を使用します。
何時間も研究した後、解決策を見つけました。いつも目の前にありました:) backStackで見つかった場合、特定の宛先にナビゲートするpopBackStack(destination, inclusive)
という関数があります。ブール値を返すため、コントローラーがフラグメントを見つけられない場合は、手動でナビゲートできます。
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)
}
Googleサンプルのリンク NavigationExtensionsをアプリケーションにコピーして、サンプルごとに設定します。よく働く。
@ piotr-prusが提供するソリューションは私を助けましたが、現在の宛先チェックを追加する必要がありました。
if (navController.currentDestination?.id == resId) {
return //do not navigate
}
このチェックなしでは、誤ってナビゲートした場合、バックスタックで見つからないため、現在の宛先が再作成されます。
@STAR_ZEROが提供するリンクを使用しましたが、正常に機能します。戻るボタンに問題がある場合は、アクティビティ/ナビゲーションホストでこのように処理できます。
override fun onBackPressed() {
if(navController.currentDestination!!.id!=R.id.homeFragment){
navController.navigate(R.id.homeFragment)
}else{
super.onBackPressed()
}
}
現在の宛先がルート/ホームフラグメント(通常、下部ナビゲーションビューの最初のフラグメント)であるかどうかを確認します。そうでない場合は、フラグメントに戻ります。
ところで、このソリューションはkeep_state_fragmentを使用して、STAR_ZEROが提供する上記のソリューションリンクと連携する必要があります。
現在のところ利用できません。
回避策として、取得したすべてのデータをビューモデルに保存し、フラグメントを再作成するときにそのデータをすぐに使用できるようにすることができます。アクティビティコンテキストを使用してビューを取得してください。
LiveDataを使用して、データライフサイクルを認識できるようにすることができます