Saya mencoba menggunakan komponen navigasi baru. Saya menggunakan BottomNavigationView dengan navController: NavigationUI.setupWithNavController (bottomNavigation, navController)
Tetapi ketika saya mengganti fragmen, mereka setiap kali menghancurkan / membuat bahkan jika mereka sebelumnya digunakan.
Apakah ada cara untuk tetap menghidupkan tautan fragmen utama kami ke BottomNavigationView?
android
navigation
bottomnavigationview
IdAndro
sumber
sumber
Jawaban:
Coba ini.
Navigator
Buat navigator khusus.
@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
Buat NavHostFragment kustom.
class CustomNavHostFragment: NavHostFragment() { override fun onCreateNavController(navController: NavController) { super.onCreateNavController(navController) navController.navigatorProvider += PersistentNavigator(context!!, childFragmentManager, id) } }
navigation.xml
Gunakan tag kustom, bukan tag fragmen.
<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>
tata letak aktivitas
Gunakan CustomNavHostFragment sebagai ganti 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>
Memperbarui
Saya membuat proyek sampel. tautan
Saya tidak membuat NavHostFragment kustom. Saya menggunakan
navController.navigatorProvider += navigator
.sumber
fragments
digunakan kembali, tidak dibuat ulang), ada masalah dengan navigasi. Masing-masingmenuitem
inbottomnavigationview
dianggap utama - jadi, saatBACK
ditekan, aplikasi selesai (atau beralih ke komponen atas). Solusi yang lebih baik adalah berperilaku seperti aplikasi YouTube: (1) Ketuk Beranda; (2) Ketuk Trending; (3) Ketuk Kotak Masuk; (4) Ketuk Trending; (5) KetukBACK
- pergi ke Kotak Masuk; (6) KetukBACK
- pergi ke Rumah; (7) KetukBACK
- aplikasi ada. Singkatnya,BACK
fungsi YouTube antara "menuitems
" kembali ke yang terbaru, tanpa mengulang item.app:navGraph
NavHostFragment aktivitas Anda.Tautan sampel Google Cukup salin NavigationExtensions ke aplikasi Anda dan konfigurasikan dengan contoh. Bekerja dengan baik.
sumber
Setelah berjam-jam penelitian saya menemukan solusi. Itu semua waktu tepat di depan kami :) Ada fungsi:
popBackStack(destination, inclusive)
yang menavigasi ke tujuan tertentu jika ditemukan di backStack. Ini mengembalikan Boolean, jadi kita bisa menavigasi ke sana secara manual jika pengontrol tidak akan menemukan fragmen.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) }
sumber
Jika Anda kesulitan menyampaikan argumen, tambahkan:
fragment.arguments = args
di kelas
KeepStateNavigator
sumber
Tidak tersedia untuk sekarang.
Sebagai solusinya, Anda dapat menyimpan semua data yang diambil ke dalam model tampilan dan menyediakan data tersebut saat Anda membuat ulang fragmen. Pastikan Anda mendapatkan tampilan menggunakan konteks aktivitas.
Anda dapat menggunakan LiveData untuk membuat data Anda sadar siklus proses
sumber
Saya telah menggunakan tautan yang disediakan oleh @STAR_ZERO dan berfungsi dengan baik. Bagi yang bermasalah dengan tombol kembali, Anda bisa mengatasinya di aktivitas / nav host seperti ini.
override fun onBackPressed() { if(navController.currentDestination!!.id!=R.id.homeFragment){ navController.navigate(R.id.homeFragment) }else{ super.onBackPressed() } }
Cukup periksa apakah tujuan saat ini adalah fragmen root / home Anda (biasanya yang pertama di tampilan navigasi bawah), jika tidak, cukup navigasikan kembali ke fragmen tersebut, jika ya, hanya keluar dari aplikasi atau lakukan apa pun yang Anda inginkan.
Btw, solusi ini perlu bekerja sama dengan tautan solusi di atas yang disediakan oleh STAR_ZERO, menggunakan keep_state_fragment .
sumber
Solusi yang diberikan oleh @ piotr-prus membantu saya, tetapi saya harus menambahkan beberapa pemeriksaan tujuan saat ini:
if (navController.currentDestination?.id == resId) { return //do not navigate }
tanpa pemeriksaan ini, tujuan saat ini akan dibuat ulang jika Anda salah menavigasi ke sana, karena tidak akan ditemukan di back-stack.
sumber
Menurut Dokumentasi Android ,
Ubah nav_host_fragment Anda menjadi -> FragmentContainerView dan dalam mengambil navController
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController
Anda dapat mempertahankan status fragmen dengan Komponen Navigasi menggunakan pendekatan ini
sumber