所以我使用导航组件库设置我的
BottomNavigationView
(如这里),一切正常,每个选项卡都可以保留其后堆栈。但是,如果我添加启动屏幕 (Fragment
) 并且:
popUpInclusive
已设置为 true)然后所有选项卡不再保留其后堆栈,而且导航变得很奇怪:
Splash -> Home(第一个选项卡)-> Me(第二个选项卡)-> Home -> 按返回,它会返回到“我”,而不是退出应用程序。
PS:我使用带有单个导航图的单个活动模式。
好的,感谢@ianhanniballake,我在这里发布了我的最终解决方案,关键点是
BottomNavigationView
必须是起始目的地,而不是其他条件目的地,例如登录或启动屏幕。
第 1 步:创建并设置 Splash 布局和片段
将
SplashFragment
添加到导航图中。
无需从
HomeFragment
-> SplashFragment
创建动作,除非您需要过渡动画
第2步.设置
MainViewModel
(共享ViewModel
)
class MainViewModel : ViewModel() {
private var _isFirstLaunch = true //replace with the real condition in the future
val isFirstLaunch: Boolean //will be accessed by SplashFragment and HomeFragment
get() = _isFirstLaunch
fun updateIsFirstLaunch(isFirstLaunch: Boolean) {
_isFirstLaunch = isFirstLaunch
}
}
步骤 3. 设置
HomeFragment
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
private lateinit var mainViewModel: MainViewModel //shared ViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
if (mainViewModel.isFirstLaunch) {
findNavController().navigate(R.id.splashFragment) //no need action, unless you want transition animation
}
binding.goButton.setOnClickListener {
findNavController().navigate(R.id.action_homeFragment_to_home2Fragment)
}
return binding.root
}
}
步骤 4. 设置
SplashFragment
class SplashFragment : Fragment() {
private lateinit var binding: FragmentSplashBinding
private lateinit var mainViewModel: MainViewModel //shared ViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_splash, container, false)
mainViewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
binding.exitSplashButton.setOnClickListener {
mainViewModel.updateIsFirstLaunch(false) //update the condition
findNavController().navigateUp() //go back to HomeFragment
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
requireActivity().finish()
}
return binding.root
}
}
我解决这个问题如下:
创建 2 个导航图:
navigation/splash_nav_graph.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/splash_nav_graph"
app:startDestination="@id/splashFragment">
<fragment
android:id="@+id/splashFragment"
android:name="com.example.SplashFragment"
android:label="SplashFragment"
tools:layout="@layout/fragment_splash">
</fragment>
</navigation>
navigation/bottom_nav_graph.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"
android:id="@+id/bottom_nav_graph"
app:startDestination="@id/home_graph">
<include app:graph="@navigation/fragment1"/>
<include app:graph="@navigation/fragment2"/>
<include app:graph="@navigation/fragment3"/>
<include app:graph="@navigation/fragment4"/>
</navigation>
activity_main.xml
<ViewGroup>
...
<androidx.fragment.app.FragmentContainerView
android:id="@+id/navHost"
...
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation_view"
android:visibility="gone"
...
/>
</ViewGroup>
添加 android:visibility="gone" 以便 BottomNavigationView 在启动时不显示
MainActivity.kt
class MainActivity : AppCompatActivity() {
private val navController: NavController by lazy {
val navHostFragment = supportFragmentManager.findFragmentById(R.id.navHost) as NavHostFragment
navHostFragment.navController
}
override fun onCreate(savedInstanceState: Bundle?) {
...
if (savedInstanceState == null) {
navController.setGraph(R.navigation.splash_nav_graph)
} else {
startBottomNavigation()
}
}
fun startBottomNavigation() {
navController.setGraph(R.navigation.bottom_nav_graph)
binding.bottomNavigationView.apply {
isVisible = true
setupWithNavController(navController)
}
}
}
然后在 SplashFragment(或splash_nav_graph.xml 中的任何其他片段)中,转到主图:
(requireActivity() as MainActivity).startBottomNavigation()