Простая навигация по графам навигации с помощью компонента архитектуры навигации Android

Это простой пример настройки навигации, которую я не могу заставить работать с библиотекой компонентов навигации после некоторого времени исследования.

Допустим, у меня есть следующий экран:  введите описание изображения здесь

Прилепленный фрагмент вверху и фрагмент внизу находятся в своих собственных навигационных графиках, вот main_activity.xml:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/nav_sticky_top"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/navigation_graph_sticky_top" />

    <fragment
        android:id="@+id/navigation_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/nav_sticky_top"
        app:navGraph="@navigation/navigation_graph" />

</androidx.constraintlayout.widget.ConstraintLayout>

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

введите здесь описание изображения

Это navigation_graph.xml:

<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/navigation_graph.xml"
    app:startDestination="@id/blankFragment1">

    <fragment
        android:id="@+id/blankFragment1"
        android:name="com.example.myapplication.BlankFragment1"
        android:label="fragment_blank_fragment1"
        tools:layout="@layout/fragment_blank_fragment1">

        <action
            android:id="@+id/action_blankFragment1_to_siblingFragment"
            app:destination="@id/siblingFragment" />

    </fragment>

    <fragment
        android:id="@+id/siblingFragment"
        android:name="com.example.myapplication.SiblingFragment"
        tools:layout="@layout/fragment_sibling_fragment" />

</navigation>

Теперь я хотел бы реализовать кнопку «Перейти к полноэкранному фрагменту», которая должна переходить к полноэкранному фрагменту, который находится в отдельном, третьем навигационном графике и должен быть над графом навигации по закрепленным фрагментам и графом навигации под ним. Как этого добиться? Под этим я подразумеваю без хаков, таких как установка для видимости верхнего фрагмента навигационного графика значения GONE и переход по нижнему навигационному графику к полноэкранному фрагменту.


person janosch    schedule 23.01.2019    source источник


Ответы (1)


ОБНОВЛЕНИЕ: я больше не рекомендую этот подход. Для небольших приложений это может сработать, но я столкнулся с трудностями при попытке передать данные между разными графами навигации, размещенными внутри разных NavHostFragments. Я думаю, что самый простой путь - это «взлом» сокрытия фрагментов в макете верхнего уровня для обеспечения полноэкранного просмотра. Вы можете добавить addOnDestinationChangedListener, чтобы прослушивать места назначения, которые вы хотите использовать в полноэкранном режиме, и просто скрыть требуемый фрагмент.

ОРИГИНАЛЬНЫЙ ОТВЕТ: Я так делаю в своем приложении, и оно работает хорошо. Вы должны заключить все ваши текущие фрагменты в родительский фрагмент с main_nav_graph.xml. Например:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/main_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/main_nav_graph" />

</androidx.constraintlayout.widget.ConstraintLayout>

Тогда ваша навигация по полноэкранным фрагментам будет выглядеть так:

<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/main_nav_graph.xml"
    app:startDestination="@id/main_fullscreen">

    <fragment
        android:id="@+id/main_fullscreen"
        android:name="com.example.myapplication.MainFullscreen" >

        <action
            android:id="@+id/action_main_fullscreen_to_fullscreen2"
            app:destination="@id/fullscreen2" />

    </fragment>

    <fragment
        android:id="@+id/fullscreen2"
        android:name="com.example.myapplication.Fullscreen2" />
</navigation>

Если MainFullscreen имеет макет, подобный предоставленному вами ConstraintLayout. Просто убедитесь, что вы добавили app:defaultNavHost="true" ко всем дочерним NavHostFragments.

Затем, когда я хочу перейти от вашего blankFragment1 к полноэкранному2, я вызываю это:

Navigation.findNavController(activity!!, R.id.main_host_fragment).navigate(R.id.action_main_fullscreen_to_fullscreen2)

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

person Carson Holzheimer    schedule 11.02.2019
comment
Интересно, придется попробовать. - person janosch; 12.02.2019
comment
Просто чтобы вас предупредить. Я обнаружил в этом серьезную проблему. Аппаратная кнопка возврата не возвращает назад во вложенном узле навигации :(. Ожидание ответа от Google - person Carson Holzheimer; 13.02.2019
comment
На самом деле это не было ошибкой. Вам просто нужно добавить app:defaultNavHost="true" к обоим NavHostFragments - person Carson Holzheimer; 15.02.2019
comment
Три месяца спустя я приступил к тестированию, и он работает хорошо, спасибо. Я выпускаю свое приложение на следующей неделе, поэтому думаю, что в этот выпуск оно не войдет =) - person janosch; 07.05.2019
comment
Я больше не рекомендую этот подход. У меня возникли проблемы с передачей данных по моему приложению из-за экранов, существующих в разных графах навигации. Если возможно, я рекомендую использовать только один NavHostFragment в вашем приложении. Для этого я рекомендую скрыть фрагмент для просмотра в полноэкранном режиме. Я думаю, что с addNavigationListener это достаточно чисто, с меньшими недостатками. - person Carson Holzheimer; 03.06.2019
comment
Хм, я реализовал ваш подход в своем приложении, и у меня нет описанной вами проблемы. Я могу без проблем передавать аргументы фрагментам, находящимся в другом навигационном графе. Я использую save-args, например: val action = SecondLevelNavigationFragmentDirections.actionSecondLevelNavigationFragmentToFirstLevelSlideInBottomWebViewFragment (appBarTitle, url); Navigation.findNavController (activity, R.id.first_level_navigation_host) .navigate (action) Здесь я открываю фрагмент веб-просмотра с аргументами из фрагмента, который находится в графе навигации нижнего уровня. - person janosch; 03.06.2019