Android Jetpack Navigation с ViewPager и TabLayout
Для нового приложения я использую навигационную библиотеку Jetpack для правильной обратной навигации. Первый уровень навигации - это навигационный ящик, который отлично работает с навигацией JetPack, как описано в документации. Но есть еще один уровень навигации, реализованный с помощью ViewPager и TabLayout. Фрагменты, переключаемые TabLayout, содержат дополнительную линейную навигационную иерархию. Однако, похоже, поддержка ViewPager/TabLayout в Jetpack Navigation не поддерживается. Адаптер FragmentPagerAdapter должен быть реализован, а управляемый задний стек заканчивается при переключении вкладок. Существует разрыв между навигацией верхнего уровня и навигацией внутри каждой вкладки. Есть ли способ сделать эту работу с помощью Jetpack Navigation?
Ответы
Ответ 1
Что сработало для меня до сих пор:
В navigation_graph.xml
- сделайте ваш ViewPagerFragment корнем вложенного графа
- подключите входную и выходную навигацию к вложенному графику
во вложенном графике:
- добавить дочерние фрагменты ViewPager на вложенный граф
Мне не нужно было менять ViewPager, и для дочерних фрагментов были созданы направления, так что навигация возможна оттуда.
Ответ 2
Да, но вам придется реализовать свой собственный пункт назначения, реализуя класс Navigator
и переопределяя как минимум методы popBackStack()
и navigate()
.
В вашей navigate
вам нужно будет вызвать ViewPager.setCurrentTab()
и добавить его в свой задний стек. Что-то вроде:
lateinit var viewPager: ViewPager? = null // you have to provide this in the constructor
private val backstack: Deque<Pair<Int, View>> = ArrayDeque
override fun navigate(destination: Destination, args: Bundle?,
navOptions: NavOptions?, navigatorExtras: Extras?
): NavDestination? {
viewPager.currentItem = destination.id
backstack.remove(destination.id) // remove so the stack has never two of the same
backstack.addLast(destination.id)
return destination
}
В вашем popBackStack
вам придется вернуть последний выбранный элемент. Что-то вроде:
override fun popBackStack(): Boolean {
if(backstack.size() <= 1) return false
viewPager.currentItem = backstack.peekLast()
backstack.removeLast()
return true
}
Вы можете найти краткое объяснение на Android документах и этот пример пользовательского навигатора для FragmentDialog
.
После реализации ViewPagerNavigator
вам нужно будет добавить его в NavController
и настроить прослушиватели выбора представлений вкладок для вызова NavController.navigate()
.
Я надеюсь, что кто-то реализует библиотеку для всех этих общих шаблонов (ViewPager, ViewGroup, FragmentDialog), если кто-нибудь найдет ее, поместите ее в комментарии.