Граф навигации может состоять из любой комбинации следующих элементов:
- Отдельный целевой сервис, например
<fragment>. - Вложенный граф, который инкапсулирует набор связанных пунктов назначения.
- Элемент
<include>, который позволяет встроить другой файл графа навигации, как если бы он был вложенным.
Такая гибкость позволяет объединять небольшие графы навигации, чтобы сформировать полный граф навигации вашего приложения, даже если эти небольшие графы навигации предоставляются отдельными модулями.
В примерах, приведенных в этой теме, каждый модуль функции ориентирован на одну функцию и предоставляет единый граф навигации, который инкапсулирует все пункты назначения, необходимые для реализации этой функции. В рабочем приложении может быть много подмодулей более низкого уровня, которые являются деталями реализации этого модуля функций более высокого уровня. Каждый из этих модулей функций прямо или косвенно включен в модуль app. Пример многомодульного приложения, используемого в этом документе, имеет следующую структуру:
Каждый модуль функции – это автономный блок со своим графом навигации и пунктами назначения. Модуль app зависит от каждого из них, добавляя их в качестве деталей реализации в свой файл build.gradle, как показано ниже:
Яркий
dependencies { ... implementation project(":feature:home") implementation project(":feature:favorites") implementation project(":feature:settings")
Kotlin
dependencies { ... implementation(project(":feature:home")) implementation(project(":feature:favorites")) implementation(project(":feature:settings"))
Роль модуля app
Модуль app отвечает за предоставление полного графа для вашего приложения и добавление NavHost в пользовательский интерфейс. В графе навигации модуля app можно ссылаться на графы библиотеки с помощью <include>. Хотя использование <include> функционально аналогично использованию вложенного графа, <include> поддерживает графы из других модулей проекта или из проектов библиотеки, как показано в следующем примере:
<?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/nav_graph"
app:startDestination="@id/home_nav_graph">
<include app:graph="@navigation/home_navigation" />
<include app:graph="@navigation/favorites_navigation" />
<include app:graph="@navigation/settings_navigation" />
</navigation>
После того как библиотека будет включена в граф навигации верхнего уровня, вы сможете переходить к графам библиотеки по мере необходимости. Например, вы можете создать действие для перехода к графу настроек из фрагмента в графе навигации, как показано ниже:
<?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/nav_graph"
app:startDestination="@id/home_nav_graph">
<include app:graph="@navigation/home_navigation" />
<include app:graph="@navigation/favorites_navigation" />
<include app:graph="@navigation/settings_navigation" />
<fragment
android:id="@+id/random_fragment"
android:name="com.example.android.RandomFragment"
android:label="@string/fragment_random" >
<!-- Launch into Settings Navigation Graph -->
<action
android:id="@+id/action_random_fragment_to_settings_nav_graph"
app:destination="@id/settings_nav_graph" />
</fragment>
</navigation>
Если нескольким модулям функций требуется ссылаться на общий набор пунктов назначения, например граф входа, не следует включать эти общие пункты назначения в граф навигации каждого модуля функции. Вместо этого добавьте эти пункты назначения в граф навигации модуля app.
Затем каждый модуль функции может переходить между модулями функций, чтобы переходить к этим общим пунктам назначения.
В предыдущем примере действие указывает пункт назначения @id/settings_nav_graph. Этот идентификатор относится к целевой странице, определенной в графе @navigation/settings_navigation..
Навигация верхнего уровня в модуле приложения
Компонент Navigation включает класс NavigationUI.
Этот класс содержит статические методы, которые управляют навигацией с помощью верхней панели приложения, панели навигации и нижней панели навигации. Если разделы верхнего уровня состоят из элементов интерфейса, предоставляемых модулями функций, то модуль app – это подходящее место для размещения навигации и элементов интерфейса верхнего уровня. Поскольку модуль приложения зависит от модулей функций, все их пункты назначения доступны из кода, определенного в модуле приложения. Это означает, что вы можете использовать NavigationUI, чтобы связать пункты меню с пунктами назначения, если идентификатор пункта меню совпадает с идентификатором пункта назначения.
На рисунке 2 в примере модуля app в основном действии определяется BottomNavigationView. Идентификаторы пунктов меню в меню соответствуют идентификаторам графов навигации графов библиотеки:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@id/home_nav_graph"
android:icon="@drawable/ic_home"
android:title="Home"
app:showAsAction="ifRoom"/>
<item
android:id="@id/favorites_nav_graph"
android:icon="@drawable/ic_favorite"
android:title="Favorites"
app:showAsAction="ifRoom"/>
<item
android:id="@id/settings_nav_graph"
android:icon="@drawable/ic_settings"
android:title="Settings"
app:showAsAction="ifRoom" />
</menu>
Чтобы разрешить NavigationUI управлять нижней панелью навигации, вызовите setupWithNavController() из onCreate() в основном классе Activity, как показано в следующем примере:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController findViewById<BottomNavigationView>(R.id.bottom_nav) .setupWithNavController(navController) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); BottomNavigationView bottomNav = findViewById(R.id.bottom_nav); NavigationUI.setupWithNavController(bottomNav, navController); }
Теперь при нажатии на элемент нижней панели навигации NavigationUI будет переходить к соответствующему графу библиотеки.
Помните, что в целом не рекомендуется, чтобы модуль приложения имел жесткую зависимость от определенного пункта назначения, глубоко встроенного в граф навигации модулей функций. В большинстве случаев вам нужно, чтобы модуль приложения знал только о точке входа в любые встроенные или включенные графы навигации (это также относится и к модулям функций). Если вам нужно сослаться на пункт назначения, находящийся глубоко в графе навигации библиотеки, предпочтительным способом сделать это является использование ссылки на контент. Ссылки на контент – это также единственный способ перейти к пункту назначения в графе навигации другой библиотеки.
Навигация по модулям функций
Во время компиляции независимые модули функций не видят друг друга, поэтому вы не можете использовать идентификаторы для перехода к пунктам назначения в других модулях. Вместо этого используйте ссылку на контент, чтобы перейти непосредственно к целевому объекту, связанному с неявной ссылкой на контент.
Продолжая предыдущий пример, представьте, что вам нужно перейти от кнопки в модуле :feature:home к пункту назначения, вложенному в модуль :feature:settings. Для этого добавьте ссылку на контент в граф навигации, как показано ниже.
<?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/settings_nav_graph"
app:startDestination="@id/settings_fragment_one">
...
<fragment
android:id="@+id/settings_fragment_two"
android:name="com.example.google.login.SettingsFragmentTwo"
android:label="@string/settings_fragment_two" >
<deepLink
app:uri="android-app://example.google.app/settings_fragment_two" />
</fragment>
</navigation>
Затем добавьте следующий код в onClickListener кнопки во фрагменте home:
Kotlin
button.setOnClickListener { val request = NavDeepLinkRequest.Builder .fromUri("android-app://example.google.app/settings_fragment_two".toUri()) .build() findNavController().navigate(request) }
Java
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { NavDeepLinkRequest request = NavDeepLinkRequest.Builder .fromUri(Uri.parse("android-app://example.google.app/settings_fragment_two")) .build(); NavHostFragment.findNavController(this).navigate(request); } });
В отличие от навигации с использованием идентификаторов действий или пунктов назначения, вы можете перейти к любому URI на любом графике, даже между модулями.
При навигации с помощью URI обратный стек не сбрасывается. Это отличается от навигации по явным ссылкам на контент, при которой обратный стек заменяется.