Компонент навигационной архитектуры Android - значки Nav Drawer

В настоящее время я использую компонент архитектуры Android Navigation, но у меня проблема с моим Navigation Drawer, Это показывает меню гамбургера, когда в моем начальном пункте назначения, но другой Fragments показывают стрелку вверх. Я считаю, что я настроил мой navigation_graph неправильно.

Здесь вы можете увидеть мой навигационный ящик, показывающий 2 пункта, Дом и Настройки. Находясь в любом из этих фрагментов, вы должны увидеть значок гамбургера.

навигационный ящик

Однако при переходе к фрагменту настроек отображается стрелка вверх.

панель инструментов

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>

я чувствую HomeFragment а также SettingsFragment должно быть как-то связано, но я не уверен, как это определить.

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Я просто настроил это так. я звонил setupActionBarWithNavController, но я также должен сам настроить навигационный ящик и обработать 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'

Благодарю.

6 ответов

В более новых альфах (у меня 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)

куда dr это MaterialDrawer и 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, так что, вероятно, есть гораздо более приятный способ сделать это.

Боюсь, это особенность навигационной составляющей.

На панели действий также будет отображаться кнопка "Вверх", когда вы находитесь не в корневом назначении, и значок ящика в корневом назначении, автоматически анимирующийся между ними.

Если вы хотите, вы можете попробовать использовать setupWithNavController(NavigationView, NavController) и обрабатывать панель инструментов самостоятельно.

Я сделал простой пример для этого вопроса. Решение почти такое же, как ответ Всевышнего. 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)
}

Если вы хотите, вы можете попробовать использовать NavController.OnNavigatedListener и использовать приведенный ниже код для установки заголовка.

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

Не забудьте установить метку на графике навигации.

Стрелка назад появляется на фрагментах вкладок, связанных с 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. Override onOptionsItemSelected настроить меню с идентификатором android.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
    

Помните, что компонент навигационной арки все еще находится в альфа-режиме, поэтому используйте его с умом.

Я думаю, что ваши пункты меню должны быть такими:

<?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>

Надеюсь это поможет

Удачного кодирования...

Я полностью согласен с мнением здесь, но это часть библиотеки

setupActionBarWithNavController

Устанавливает ActionBar, возвращаемый AppCompatActivity.getSupportActionBar() для использования с NavController.

При вызове этого метода заголовок на панели действий будет автоматически обновляться при изменении места назначения (при условии, что существует допустимая метка).

Начальный пункт назначения вашего навигационного графика считается единственным пунктом назначения верхнего уровня. В пункте назначения начала вашего навигационного графика панель действий покажет значок ящика, если заданный DrawerLayout не равен NULL. На всех других направлениях на панели действий появится кнопка "Вверх". Вызовите navigateUp(NavController, DrawerLayout) для обработки кнопки "Вверх".

это для меня нарушено и не является желаемым результатом, поэтому то, что я делаю, все еще использует его с использованием вида навигации, используя

    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;

        }
    });

Затем я создаю новый график навигации для каждого из этих фрагментов, не очень, но я получаю желаемый результат