この問題は今度は何度か尋ねられましたが、2020年になりましたが、これに対する優れた有効な解決策はまだ見つかりましたか?
フラグメントが選択されるたびにフラグメントを更新せずに、下部のナビゲーションコントロールを使用してナビゲートできるようにしたいと思います。これが私が現在持っているものです:
navigation/main.xml:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/main"
app:startDestination="@id/home">
<fragment
Android:id="@+id/home"
Android:name="com.org.ftech.fragment.HomeFragment"
Android:label="@string/app_name"
tools:layout="@layout/fragment_home" />
<fragment
Android:id="@+id/news"
Android:name="com.org.ftech.fragment.NewsFragment"
Android:label="News"
tools:layout="@layout/fragment_news"/>
<fragment
Android:id="@+id/markets"
Android:name="com.org.ftech.fragment.MarketsFragment"
Android:label="Markets"
tools:layout="@layout/fragment_markets"/>
<fragment
Android:id="@+id/explore"
Android:name="com.org.ftech.ExploreFragment"
Android:label="Explore"
tools:layout="@layout/fragment_explore"/>
</navigation>
activity_mail.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.widget.DrawerLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<fragment
Android:id="@+id/nav_Host_fragment"
Android:name="androidx.navigation.fragment.NavHostFragment"
Android:layout_width="0dp"
Android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/main" />
<com.google.Android.material.bottomnavigation.BottomNavigationView
Android:id="@+id/bottomNavigationView"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
app:itemIconTint="@color/nav"
app:itemTextColor="@color/nav"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/main">
</com.google.Android.material.bottomnavigation.BottomNavigationView>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.Android.material.navigation.NavigationView
app:menu="@menu/main"
Android:layout_width="wrap_content"
Android:layout_height="match_parent"
Android:id="@+id/navigationView"
Android:layout_gravity="start">
</com.google.Android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
MainActivity.kt:
class MainActivity : AppCompatActivity() {
private var drawerLayout: DrawerLayout? = null
private var navigationView: NavigationView? = null
private var bottomNavigationView: BottomNavigationView? = null
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
drawerLayout = findViewById(R.id.drawer_layout)
navigationView = findViewById(R.id.navigationView)
bottomNavigationView = findViewById(R.id.bottomNavigationView)
val navController = findNavController(R.id.nav_Host_fragment)
appBarConfiguration = AppBarConfiguration(setOf(R.id.markets, R.id.explore, R.id.news, R.id.home), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
findViewById<NavigationView>(R.id.navigationView)
.setupWithNavController(navController)
findViewById<BottomNavigationView>(R.id.bottomNavigationView)
.setupWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_Host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.search) {
startActivity(Intent(applicationContext, SearchableActivity::class.Java))
}
return super.onOptionsItemSelected(item)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.options_menu, menu)
return super.onCreateOptionsMenu(menu)
}
}
フラグメントでは、onCreateView
のデータをフェッチするためにサービスを数回呼び出しています。フラグメントを再開すると、それらの呼び出しが実行されなくなり、フラグメントの状態が保持されるはずです。
このようなものを試してください
navView.setOnNavigationItemSelectedListener(onNavigationItemSelectedListener)
そして
private val onNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.home -> {
fragmentManager.beginTransaction().hide(active).show(homeFragment).commit()
active = homeFragment
return@OnNavigationItemSelectedListener true
}
R.id.news -> {
fragmentManager.beginTransaction().hide(active).show(newsFragment).commit()
active = newsFragment
return@OnNavigationItemSelectedListener true
}
R.id.markets -> {
fragmentManager.beginTransaction().hide(active).show(marketsFragment).commit()
active = marketsFragment
return@OnNavigationItemSelectedListener true
}
R.id.explore -> {
fragmentManager.beginTransaction().hide(active).show(exploreFragment).commit()
active = exploreFragment
return@OnNavigationItemSelectedListener true
}
}
false
}
NavigationUI.setupWithNavController()
を使用する場合、NavOptions
はNavigationUI.onNavDestinationSelected()
で定義されます。これらのオプションにはlaunchSingleTop
が含まれ、メニュー項目がセカンダリでない場合はpopUpTo
がグラフのルートになります。
問題は、launchSingleTop
がまだ先頭のフラグメントを新しいフラグメントに置き換えることです。この問題を解決するには、独自のsetupWithNavController()
およびonNavDestinationSelected()
関数を作成する必要があります。 onNavDestinationSelected()
では、NavOptions
をニーズに合わせて調整します。
クラスを作成します。
@Navigator.Name("keep_state_fragment") // `keep_state_fragment` is used in navigation xml
class KeepStateNavigator(
private val context: Context,
private val manager: FragmentManager, // Should pass childFragmentManager.
private val containerId: Int
) : FragmentNavigator(context, manager, containerId) {
override fun navigate(
destination: Destination,
args: Bundle?,
navOptions: NavOptions?,
navigatorExtras: Navigator.Extras?
): NavDestination? {
val tag = destination.id.toString()
val transaction = manager.beginTransaction()
var initialNavigate = false
val currentFragment = manager.primaryNavigationFragment
if (currentFragment != null) {
transaction.detach(currentFragment)
} else {
initialNavigate = true
}
var fragment = manager.findFragmentByTag(tag)
if (fragment == null) {
val className = destination.className
fragment = manager.fragmentFactory.instantiate(context.classLoader, className)
transaction.add(containerId, fragment, tag)
} else {
transaction.attach(fragment)
}
transaction.setPrimaryNavigationFragment(fragment)
transaction.setReorderingAllowed(true)
transaction.commitNow()
return if (initialNavigate) {
destination
} else {
null
}
}
}
Nav_graphでフラグメントの代わりにkeep_state_fragmentを使用
活動中:
val navController = findNavController(R.id.nav_Host_fragment)
// get fragment
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_Host_fragment)!!
// setup custom navigator
val navigator = KeepStateNavigator(this, navHostFragment.childFragmentManager, R.id.nav_Host_fragment)
navController.navigatorProvider += navigator
// set navigation graph
navController.setGraph(R.navigation.nav_graph)
bottom_navigation.setupWithNavController(navController)