17

I'm currently using the Android Architecture Component's Navigation, but I'm running into an issue with my Navigation Drawer. It shows the hamburger menu when at my starting destination, but other Fragments are showing the up arrow. I believe I've setup my navigation_graph incorrectly.

Here you can see my nav drawer, showing 2 items, Home and Settings. When in either of these Fragments, you should see the Hamburger icon.

nav drawer

However, when navigating to the Settings Fragment, it shows the Up arrow.

toolbar

navigation.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"
    app:startDestination="@id/nav_home">

    <!-- Start at HomeFragment -->
    <fragment
        android:id="@+id/nav_home"
        android:name=".HomeFragment"
        android:label="@string/home">

        <!-- Navigate to the Search -->
        <action
            android:id="@+id/action_nav_home_to_nav_search"
            app:destination="@id/nav_search" />
    </fragment>


    <fragment
        android:id="@+id/nav_settings"
        android:name=".SettingsFragment"
        android:label="@string/settings">

        <!-- Navigate to the Search -->
        <action
            android:id="@+id/action_nav_settings_to_nav_search"
            app:destination="@id/nav_search" />
    </fragment>



    <fragment
        android:id="@+id/nav_search"
        android:name=".SearchFragment"
        android:label="@string/search" />

</navigation>

I feel like HomeFragment and SettingsFragment should be related somehow but I'm not sure how to define that.

main_drawer.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item
            android:id="@id/nav_home"
            android:icon="@drawable/ic_home_white_24dp"
            android:title="@string/home" />

        <item
            android:id="@id/nav_settings"
            android:icon="@drawable/ic_settings_white_24dp"
            android:title="@string/settings" />
    </group>
</menu>

MainActivity

And then within MainActivity, I just set it up like this. I called setupActionBarWithNavController, but I also have to actually setup the nav drawer myself, and handle the onNavigationItemSelected.

private fun setupNavigation() {
    navController = findNavController(R.id.mainNavigationFragment)
    setupActionBarWithNavController(this, navController, drawer_layout)

    val toggle = ActionBarDrawerToggle(
                this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
        drawer_layout.addDrawerListener(toggle)
        toggle.syncState()

    nav_view.setNavigationItemSelectedListener(this)
}

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    val current = navController.currentDestination.id
    if (item.itemId != current) {
        navController.navigate(item.itemId)
    }

    drawer_layout.closeDrawers()
    return true
}

build.gradle

// Navigation
implementation 'android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha04'
implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0-alpha04'

Thanks.

4

7 回答 7

10

在较新的 alpha(我有 1.0.0-alpha07)中,它们增加了topLevelDestinationIds在调用AppBarConfiguration构造函数时定义的可能性。

所以我像这样设置我的 NavController

    val navController = findNavController(R.id.nav_host_fragment)
    val config = AppBarConfiguration(
        setOf(
            R.id.fistTopFragment,
            R.id.secondTopFragment,
            ...
        ),
        dr.drawerLayout
    )
    tb.setupWithNavController(navController, config)

drMaterialDrawer 和工具栏在哪里tb

然后它的行为更像 Gmail,至少对于ActionBarDrawerToggle,后堆栈仍然保留。由于我必须自己处理 MaterialDrawer 中的项目选择,因此我将使用包含 popTo 的全局导航操作将返回堆栈操作减少到导航图的根片段,并暂时使用类似“欢迎屏幕”之类的东西。

另一种方法可能是自定义处理onBackPressed. 您必须首先app:defaultNavHost="true"从活动布局中的主机片段中删除。像这样的东西

override fun onBackPressed() {
    val navController = findNavController(R.id.nav_host_fragment)
    if (navController.currentDestination == null
        || navController.currentDestination!!.id in setOf(
            R.id.fistTopFragment,
            R.id.secondTopFragment,
            ...
        )
    ) {
        super.onBackPressed()
    } else {
        navController.navigateUp()
    }
}

对不起代码,我还在学习 Kotlin,所以可能有更好的方法来做这件事。

于 2018-11-16T18:51:10.583 回答
4

恐怕是导航组件的一个特性

当您位于非根目的地时,操作栏还将显示向上按钮,当您位于根目的地时,将显示抽屉图标,并在它们之间自动生成动画。

如果需要,可以尝试使用setupWithNavController(NavigationView, NavController)并自己处理工具栏。

于 2018-07-31T09:11:08.407 回答
2

我为这个问题做了一个简单的例子。解决方案与全能者的答案几乎相同。https://github.com/isaul32/android-sunflower

首先创建一组顶级目的地

val topLevelDestinations = setOf(R.id.garden_fragment,
        R.id.plant_list_fragment)
appBarConfiguration = AppBarConfiguration.Builder(topLevelDestinations)
        .setDrawerLayout(drawerLayout)
        .build()

然后像这样覆盖 onSupportNavigateUp 函数

override fun onSupportNavigateUp(): Boolean {
    return NavigationUI.navigateUp(navController, appBarConfiguration)
}
于 2018-12-09T18:53:47.470 回答
1

出现在与关联的选项卡片段上的后退箭头BottomNavigationView是预期的行为。然而,即使在著名的应用程序(Instagram、Youtube 都有底部标签)中,也没有看到它被“按原样”使用。例如,如果您导航到 Youtube 应用程序中的不同底部选项卡并单击设备返回选项,您会注意到它转到上一个选项卡片段而不退出应用程序。所以bottomnavigationview选项卡片段不是这里的根目的地。

想要提醒您在前进时可能遇到的其他重要问题:

但是,您可以使用几个钩子来自定义行为:

  1. onBackPressed- 如果打开则关闭抽屉布局

    override fun onBackPressed() {
        if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
          drawerLayout.closeDrawer(GravityCompat.START)
        } else {
          super.onBackPressed()
        }
     }
    
  2. 添加navController.addOnNavigatedListener(..)并在监听器内部自定义 HomeAsUpIndicator 图标

  3. 覆盖onOptionsItemSelected以使用 idandroid.R.id.home操作自定义菜单

  4. 设置自定义片段导航器以自定义片段的处理方式(替换或显示/隐藏)

    navHostFragment = supportFragmentManager
            .findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment? ?: return
    val customNavigator = CustomFragmentNavigator(navHostFragment.requireContext(),
            navHostFragment.childFragmentManager, navHostFragment.id)
    navHostFragment.navController.navigatorProvider.addNavigator(customNavigator)
    
    val inflater = navHostFragment.navController.navInflater
    val graph = inflater.inflate(R.navigation.main_nav_graph)
    navHostFragment.navController.graph = graph
    

请记住,导航拱组件仍处于 alpha 阶段,因此请明智地使用它。

于 2018-08-03T04:52:43.283 回答
1

如果需要,可以使用NavController.OnNavigatedListener并使用以下代码设置标题。

@Override
public void onNavigated(@NonNull NavController controller, @NonNull NavDestination destination) {
    mActivityBinding.toolbar.setTitle(destination.getLabel());
}

请记住在导航图中设置标签。

于 2018-09-26T13:20:24.097 回答
0

我认为您的菜单项应该是这样的:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
            android:id="@id/nav_home"
            android:icon="@drawable/ic_home_white_24dp"
            android:title="@string/home" />

        <item
            android:id="@id/nav_settings"
            android:icon="@drawable/ic_settings_white_24dp"
            android:title="@string/settings" />

</menu>

希望这可以帮助

快乐的编码...

于 2018-08-03T10:57:28.077 回答
0

我完全同意这里的观点,但它是图书馆的一部分

setupActionBarWithNavController

设置 AppCompatActivity.getSupportActionBar() 返回的 ActionBar 以与 NavController 一起使用。

通过调用这个方法,当目的地改变时,动作栏中的标题会自动更新(假设有一个有效的标签)。

导航图的起始目的地被认为是唯一的顶级目的地。如果给定的 DrawerLayout 不为 null,则在导航图的起始目的地上,ActionBar 将显示抽屉图标。在所有其他目的地上,ActionBar 将显示向上按钮。调用 navigateUp(NavController, DrawerLayout) 来处理 Up 按钮。

这对我来说是坏的,而不是预期的结果,所以我正在做的仍然是使用导航视图使用它

    navController = Navigation.findNavController(this, R.id.nav_host);
    NavigationUI.setupWithNavController(navigationView,navController);

然后有一个听众来更新标题和我想要改变的任何其他内容

   navController.addOnNavigatedListener((controller, destination) -> {
        setToolbarColour(R.color.primary);
        switch (destination.getId()){
            case R.id.dashBoard :
                setToolbarColour(android.R.color.transparent);
                break;
            case R.id.requests :
                toolbar.setTitle(getString(R.string.request));
                break;

        }
    });

然后我为这些片段中的每一个创建一个新的导航图,不是很好,但我得到了我想要的结果

于 2018-10-31T09:07:09.333 回答