Android BottomNavigationView 与闪屏返回堆栈问题

问题描述 投票:0回答:2

所以我使用导航组件库设置我的

BottomNavigationView
(如这里),一切正常,每个选项卡都可以保留其后堆栈。但是,如果我添加启动屏幕 (
Fragment
) 并且:

  1. 将其设置为起始目的地(
    popUpInclusive
    已设置为 true)
  2. 创建从 SplashFragment 到第一个选项卡 HomeFragment
  3. 的操作

然后所有选项卡不再保留其后堆栈,而且导航变得很奇怪:

Splash -> Home(第一个选项卡)-> Me(第二个选项卡)-> Home -> 按返回,它会返回到“我”,而不是退出应用程序。

PS:我使用带有单个导航图的单个活动模式。

android android-navigation android-navigation-graph android-bottomnavigationview android-splashscreen
2个回答
1
投票

好的,感谢@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
    }
}

演示:https://youtu.be/AxiIsY6BtGg


0
投票

我解决这个问题如下:

创建 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()
© www.soinside.com 2019 - 2024. All rights reserved.