当前位置: 首页 > 知识库问答 >
问题:

设置底部导航视图导航组件时出现问题

束建章
2023-03-14

我正在将我的应用程序转换为使用一个活动并添加了BottomNavigationView,并努力防止在片段之间导航时重新创建片段,进行不必要的api调用。但是我无法使它工作:

  • 不显示片段
  • 图标未切换
  • 触摸底部菜单项不会切换片段
  • 触摸所选项目会使应用崩溃,并带有 TypeCastException: kotlin。TypeCastException: null 不能强制转换为非 null 类型 androidx.navigation.fragment.NavHostFragment at com.example.testapp.NavigationExtensionsKt$setupItemReselected$1.onNavigationItemReselected

活动的布局:

<androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/nav_view"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="0dp"
        android:layout_marginStart="0dp"
        app:menu="@menu/bottom_nav_menu" />

底部导航菜单:

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_1"
        android:icon="@drawable/ic_1"
        android:title="@string/title_1" />

    <item
        android:id="@+id/homeFragment"
        android:icon="@drawable/ic_2"
        android:title="@string/home" />

    <item
        android:id="@+id/navigation_3"
        android:icon="@drawable/ic_3"
        android:title="@string/title_3" />
</menu>

在主活动中:

    class MainActivity : DaggerAppCompatActivity() {

    private var currentNavController: LiveData<NavController>? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        nav_view.itemIconTintList = null

        if(savedInstanceState == null){
            setupBottomNavigationBar()
        } // Else, need to wait for onRestoreInstanceState

    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        // Now that BottomNavigationBar has restored its instance state
        // and its selectedItemId, we can proceed with setting up the
        // BottomNavigationBar with Navigation
        setupBottomNavigationBar()
    }

    private fun setupBottomNavigationBar() {
        val bottomNavigationView = findViewById<BottomNavigationView>(R.id.nav_view)

        val navGraphIds = listOf(R.navigation.mobile_navigation, R.navigation.settings)
        val menuItemsIds = listOf(R.id.navigation_1, R.id.homeFragment, R.id.navigation_3)
        val defaultIconsIds = listOf(R.drawable.ic_1,  R.drawable.ic_2, R.drawable.ic_3)
        val selectedIconsIds = listOf(R.drawable.ic_1a, R.drawable.ic_2a, R.drawable.ic_3a)

        // Setup the bottom navigation view with a list of navigation graphs (custom extension)
        val controller = bottomNavigationView.setupWithNavController(
            navGraphIds = navGraphIds,
            menuItemsIds = menuItemsIds,
            defaultIconsIds = defaultIconsIds,
            selectedIconsIds = selectedIconsIds,
            fragmentManager = supportFragmentManager,
            containerId = R.id.nav_host_container,
            intent = intent
        )

        currentNavController = controller

        // updating icons
        nav_view.menu.iterator().forEach {
            if (it.isChecked) {
                it.setIcon(selectedIconsIds[menuItemsIds.indexOf(it.itemId)])
            } else {
                it.setIcon(defaultIconsIds[menuItemsIds.indexOf(it.itemId)])
            }
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        return currentNavController?.value?.navigateUp() ?: false
    }
}

导航扩展:

   //.....
    //....

    private fun BottomNavigationView.setupItemReselected(
    menuItemsIds: List<Int>,
    defaultIconsIds: List<Int>,
    selectedIconsIds: List<Int>,
    graphIdToTagMap: SparseArray<String>,
    fragmentManager: FragmentManager) {
    setOnNavigationItemReselectedListener { item ->

        this.menu.iterator().forEach { it ->
            it.setIcon(defaultIconsIds[menuItemsIds.indexOf(it.itemId)])
        }

        item.setIcon(selectedIconsIds[menuItemsIds.indexOf(item.itemId)])

        val newlySelectedItemTag = graphIdToTagMap[item.itemId]
        val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag) as NavHostFragment //TypeCastException happens here
        val navController = selectedFragment.navController
        // Pop the back stack to the start destination of the current navController graph
        navController.popBackStack(
            navController.graph.startDestination, false
        )
    }
}

屏幕为空白,未呈现任何片段视图。

有人能帮我解决这个问题吗?我错过什么了吗?

PS:代码取自可在此处找到的开源应用程序

[编辑]添加导航图:

>

  • mobile_navigation

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.testapp.homeFragment"
        android:label="@string/home"
        tools:layout="@layout/home_fragment" >
    
        <action
            android:id="@+id/homrFragment_to_detailsFragment"
            app:launchSingleTop="true"
            app:enterAnim="@anim/fragment_open_enter"
            app:exitAnim="@anim/fragment_open_exit"
            app:destination="@id/detailsFragment" />
    </fragment>
    
    <fragment
        android:id="@+id/navigation_1"
        android:name="com.example.testapp.Fragment_S"
        android:label="@string/fragment_s"
        tools:layout="@layout/fragment_s" >
        <action
           android:id="@+id/action_navigation_1_to_detailsFragment"
            app:destination="@id/detailsFragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_in_left" />
    </fragment>
    
    <fragment
        android:id="@+id/navigation_3"
        android:name="com.example.testapp.Fragment3"
        android:label="@string/fragment_ss"
        tools:layout="@layout/fragment_ss" />
    
    
    <dialog
        android:id="@+id/detailsFragment"
        android:name="com.example.testapp.DetailsFragment"
        android:label="InDetails"
        tools:layout="@layout/layout_details">
    
        <argument
            android:name="arg1"
            android:defaultValue=""
            app:argType="string"/>
    
        <argument
            android:name="arg2"
            android:defaultValue=""
            app:argType="string" />
    </dialog>
    

    导航设置:

     <?xml version="1.0" encoding="utf-8"?>
    
  • 共有1个答案

    吕永嘉
    2023-03-14

    使用导航组件设置 BottomNavigationView 可能有点棘手,但我认为您作为示例遵循的代码有点过度设计,并且/或者用于比初始代码更复杂的目的。

    我会在评论中问(没有足够的代表),但是你也能发布导航图吗?一旦你正确设置了导航图、菜单和布局,设置导航控制器就非常容易,但是所有这些都必须一丝不苟地同步,并且这方面的留档并不是很好。

    在您回复navgraph之前,我会尝试帮助您解决问题:

    首先,改变你的想法

    <androidx.fragment.app.FragmentContainerView
    

    <fragment
    

    但添加以下标签:

            android:name="androidx.navigation.fragment.NavHostFragment"
            app:navGraph="@navigation/your_nav_graph.xml"
    

    然后,确保菜单上的 id.xml与所需目的地的相同 ID 匹配,如导航图中所述,例如,您应该有 3 个目的地,称为

    android:id="@+id/navigation_1"
    
    android:id="@+id/homeFragment"
    
    android:id="@+id/navigation_3"
    

    您不需要设置任何操作。

    之后,只需在具有 BottomNavigationView 的活动中执行此命令:

    NavigationUI.setupWithNavController(your_bottom_navigation_view, findNavController(R.id.your_navigation_fragment))
    

    在此之后,导航应该可以正常工作,而无需在“setupBottomNavigationView()”方法或您还发布的导航扩展上设置所有内容。

    这样,导航就可以处理所有事情,从背景栈到在BottomNavigationView上突出显示正确的按钮。

     类似资料:
    • 我的应用程序有问题。我有一个底部导航视图,包含3个不同的片段,尽管目前只有主要的内容。当我试图从左侧的两个片段中的一个移动到主视图时,问题就出现了,即当底部导航视图被隐藏时。我附上了主代码。 PD:我有25.3.1版本的所有库(如果有用的话)。 感谢您的关注。 activity\u main。xml 主要活动。Java语言 我也给你添加了两张图片。 Ofertas片段 主片段

    • 但是,当我初始化BottomNavigationView时,我会得到: 我正在从一个片段初始化BottomNativigationView。我猜这就是问题所在,但我想不出解决办法。 下面是为片段设置导航的活动的BottomNavigationView xml。

    • 底部导航 (同首页导航,当你没有做到足够好的商品关联时,只要你精心设置好你的网站导航,它就可以让你店铺的各个页面串联起来,方便买家在栏目间快速切换,引导买家前往您期望的页面。) 底部导航主要包括:展示页面(对底部导航的添加及删除)、文字颜色、选中颜色、菜单名称(可自定义)、链接地址(引导买家前往您期望的页面)。

    • 我的天气应用程序上有一个底部导航视图,其中包含3个面板(今天,每小时 以下是问题的说明: 我希望无论单击那些导航视图,数据都保持不变。 我试过使用https://stackoverflow.com/a/60201555/16020235建议但它失败了,只有一个例外: 我发现很难实现他的代码,关于这个问题的其余建议都是用kotlin编写的。 拜托我该怎么解决这件事? 以下是我的代码: my_nav.

    • 这就是我要开始的。所选项目应为主页(中间) 我在OnCreate下有这个 而这个外部Oncreate

    • 本文向大家介绍Flutter实现底部导航,包括了Flutter实现底部导航的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Flutter实现底部导航的具体代码,供大家参考,具体内容如下 BottomNavigationBar使用 底部导航栏 主文件 main.dart (注意导入文件路径) 底部包含三个导航按钮,分别对应三个界面: firstPage.dart secondPage.