新しいナビゲーションコンポーネントを使用しようとしています。navControllerでBottomNavigationViewを使用します:NavigationUI.setupWithNavController(bottomNavigation、navController)
しかし、フラグメントを切り替えると、以前に使用されていたとしても、毎回破棄/作成されます。
BottomNavigationViewへのメインフラグメントリンクを存続させる方法はありますか?
新しいナビゲーションコンポーネントを使用しようとしています。navControllerでBottomNavigationViewを使用します: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
。
fragments
再作成ではなく再利用されます)、ナビゲーションに問題があります。それぞれmenuitem
には、bottomnavigationview
一次と見なされる-このように、BACK
押圧され、アプリの終了(又は上部コンポーネントになります)。より良い解決策は、YouTubeアプリと同じように動作することです。(1)[ホーム]をタップします。(2)[トレンド]をタップします。(3)[受信トレイ]をタップします。(4)[トレンド]をタップします。(5)タップBACK
-受信トレイに移動します。(6)タップBACK
-ホームに移動します。(7)タップBACK
-アプリが存在します。要約すると、BACK
「menuitems
」の間のYouTube機能は、アイテムを繰り返さずに最新のものに戻ります。
app:navGraph
、アクティビティのNavHostFragmentから削除するのを忘れていました。
Googleのサンプルリンク NavigationExtensionsをアプリケーションにコピーし、例を使用して構成するだけです。よく働く。
何時間も研究した後、私は解決策を見つけました。それはいつも私たちの目の前にありました:)popBackStack(destination, inclusive)
backStackで見つかった場合に指定された宛先にナビゲートする機能があります。ブール値を返すため、コントローラーがフラグメントを見つけられない場合は、手動でナビゲートできます。
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)
}
引数の受け渡しに問題がある場合は、以下を追加してください。
fragment.arguments = args
クラスで KeepStateNavigator
現在ご利用いただけません。
回避策として、フェッチしたすべてのデータをビューモデルに保存し、フラグメントを再作成するときにそのデータをすぐに利用できるようにすることができます。アクティビティコンテキストを使用してビューを取得するようにしてください。
LiveDataを使用して、データのライフサイクルを認識できるようにすることができます
@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によって提供される上記のソリューションリンクと連携する必要があります。
@ piotr-prusによって提供された解決策は私を助けました、しかし私はいくつかの現在の目的地チェックを追加しなければなりませんでした:
if (navController.currentDestination?.id == resId) {
return //do not navigate
}
このチェックを行わないと、現在の宛先が誤ってナビゲートされた場合に再作成されます。これは、バックスタックで見つからないためです。
Androidのドキュメントによると、
FragmentContainerViewを使用してNavHostFragmentを作成する場合、またはFragmentTransactionを介してNavHostFragmentをアクティビティに手動で追加する場合、Navigation.findNavController(Activity、@ IdRes int)を介してアクティビティのonCreate()でNavControllerを取得しようとすると失敗します。代わりに、NavControllerFragmentから直接NavControllerを取得する必要があります。
> -にあなたのnav_host_fragmentを変更FragmentContainerView とretriveからNavControllerに
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
このアプローチを使用して、ナビゲーションコンポーネントでフラグメントの状態を保持できます。