Android Jetpack Navigation, BottomNavigationView с автоматическим фрагментом обратного стека при нажатии кнопки возврата?
То, что я хотел, после выбора нескольких вкладок одна за другой пользователем, и пользователь, нажимающий кнопку «Назад», приложение должно перенаправлять на последнюю страницу, которую он / она открывал.
Я добился того же с помощью Android ViewPager, сохранив текущий выбранный элемент в ArrayList. Есть ли какой-либо автоматический возвратный стек после выпуска Android Jetpack Navigation Release? Я хочу добиться этого с помощью навигационного графика
activity_main.xml
<?xml version = "1.0" encoding = "utf-8"?>
<android.support.constraint.ConstraintLayout 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/container"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".main.MainActivity">
<fragment
android:id = "@+id/my_nav_host_fragment"
android:name = "androidx.navigation.fragment.NavHostFragment"
android:layout_width = "match_parent"
android:layout_height = "0dp"
app:defaultNavHost = "true"
app:layout_constraintBottom_toTopOf = "@+id/navigation"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent"
app:navGraph = "@navigation/nav_graph" />
<android.support.design.widget.BottomNavigationView
android:id = "@+id/navigation"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_marginStart = "0dp"
android:layout_marginEnd = "0dp"
android:background = "?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintRight_toRightOf = "parent"
app:menu = "@menu/navigation" />
</android.support.constraint.ConstraintLayout>
navigation.xml
<?xml version = "1.0" encoding = "utf-8"?>
<menu xmlns:android = "http://schemas.android.com/apk/res/android">
<item
android:id = "@+id/navigation_home"
android:icon = "@drawable/ic_home"
android:title = "@string/title_home" />
<item
android:id = "@+id/navigation_people"
android:icon = "@drawable/ic_group"
android:title = "@string/title_people" />
<item
android:id = "@+id/navigation_organization"
android:icon = "@drawable/ic_organization"
android:title = "@string/title_organization" />
<item
android:id = "@+id/navigation_business"
android:icon = "@drawable/ic_business"
android:title = "@string/title_business" />
<item
android:id = "@+id/navigation_tasks"
android:icon = "@drawable/ic_dashboard"
android:title = "@string/title_tasks" />
</menu>
также добавил
bottomNavigation.setupWithNavController(Navigation.findNavController(this, R.id.my_nav_host_fragment))
Я получил один ответ от Levi Moreira, а именно:
navigation.setOnNavigationItemSelectedListener {item ->
onNavDestinationSelected(item, Navigation.findNavController(this, R.id.my_nav_host_fragment))
}
Но при этом происходит только повторное создание экземпляра последнего открытого фрагмента.
Обеспечение правильной обратной навигации для BottomNavigationView
еще не получил ответа
Комментируя немного поздно, но после некоторого рытья я обнаружил, что popBackStack вызывается из функции NavController.navigate(), когда NavOptions не равны нулю. Я предполагаю, что на данный момент это невозможно сделать из коробки. Требуется специальная реализация NavController, которая обращается к mBackStack через отражение или что-то в этом роде.
Если вы добавите слушателя в нижнюю навигацию, вы можете переопределить навигацию, чтобы он возвращал стек, если стек уже содержит новое место назначения, или иным образом выполнять обычную навигацию, если это не так. if (!navHost.popBackStack(it.itemId, false)) navHost.navigate(it.itemId)
Обход проблемы с воссозданием фрагмента - stackoverflow.com/a/51684125/6024687
Вы нашли какой-нибудь способ добиться этого?
Вы можете настроить viewpager с нижним навигационным представлением. Каждый фрагмент в окне просмотра будет фрагментом контейнера, у него будут дочерние фрагменты со своим собственным стеком. Таким образом, вы можете поддерживать backstack для каждой вкладки в окне просмотра.
Я использовал этот способ, но запуск приложения занимает слишком много времени до первого запуска
Тогда вы, должно быть, делаете что-то не так, убедитесь, что вы не выполняете тяжелую работу при oncreate или oncreateview фрагментов. Нет никакого способа, чтобы это заняло время
Мне нужно загрузить содержимое, я не думаю, что YouTube или Instagram использовали ViewPager
Это определенно просмотрщик. Просто прокрутите одну страницу и попробуйте переключать вкладки, это очень быстро и возобновляется из того же состояния. Вы не можете добиться этого, изменив фрагменты в одном контейнере, это несколько фрагментов, просматриваемых с помощью окна просмотра.
Я также предполагаю, что YouTube или Instagram не используют ViewPager. Восстановление происходит из-за всплывающего действия backStack, которое возобновляет базовый фрагмент, который добавлен в первую очередь, а не заменен.
Вам действительно не нужен ViewPager для работы с BottomNavigation и новым компонентом архитектуры навигации. Я работал над образцом приложения, в котором используются ровно два, см. здесь.
Основная концепция заключается в том, что у вас есть основное действие, на котором будет размещаться BottomNavigationView, и это узел навигации для вашего навигационного графика, вот как выглядит xml для него:
activity_main.xml
<?xml version = "1.0" encoding = "utf-8"?>
<android.support.constraint.ConstraintLayout 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/container"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".main.MainActivity">
<fragment
android:id = "@+id/my_nav_host_fragment"
android:name = "androidx.navigation.fragment.NavHostFragment"
android:layout_width = "match_parent"
android:layout_height = "0dp"
app:defaultNavHost = "true"
app:layout_constraintBottom_toTopOf = "@+id/navigation"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent"
app:navGraph = "@navigation/nav_graph" />
<android.support.design.widget.BottomNavigationView
android:id = "@+id/navigation"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_marginStart = "0dp"
android:layout_marginEnd = "0dp"
android:background = "?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintRight_toRightOf = "parent"
app:menu = "@menu/navigation" />
</android.support.constraint.ConstraintLayout>
Меню навигации (меню вкладок) для BottomNavigationView выглядит следующим образом:
navigation.xml
<?xml version = "1.0" encoding = "utf-8"?>
<menu xmlns:android = "http://schemas.android.com/apk/res/android">
<item
android:id = "@+id/navigation_home"
android:icon = "@drawable/ic_home"
android:title = "@string/title_home" />
<item
android:id = "@+id/navigation_people"
android:icon = "@drawable/ic_group"
android:title = "@string/title_people" />
<item
android:id = "@+id/navigation_organization"
android:icon = "@drawable/ic_organization"
android:title = "@string/title_organization" />
<item
android:id = "@+id/navigation_business"
android:icon = "@drawable/ic_business"
android:title = "@string/title_business" />
<item
android:id = "@+id/navigation_tasks"
android:icon = "@drawable/ic_dashboard"
android:title = "@string/title_tasks" />
</menu>
Все это просто установка BottomNavigationView. Теперь, чтобы заставить его работать с компонентом Navigation Arch, вам нужно войти в редактор графа навигации, добавить все места назначения фрагментов (в моем случае у меня их 5, по одному для каждой вкладки) и установить идентификатор места назначения с тем же имя как в файле navigation.xml:
Это скажет Android установить связь между вкладкой и фрагментом, теперь каждый раз, когда пользователь щелкает вкладку «Главная», Android будет заботиться о загрузке правильного фрагмента.
Также есть один фрагмент кода kotlin, который необходимо добавить в ваш NavHost (основное действие) для подключения к BottomNavigationView:
Вам нужно добавить в свой onCreate:
bottomNavigation.setupWithNavController(Navigation.findNavController(this, R.id.my_nav_host_fragment))
Это сообщает Android, что необходимо выполнить соединение между компонентом архитектуры навигации и BottomNavigationView. См. Больше в документы.
Чтобы получить такой же внешний вид, как при использовании YouTube, просто добавьте это:
navigation.setOnNavigationItemSelectedListener {item ->
onNavDestinationSelected(item, Navigation.findNavController(this, R.id.my_nav_host_fragment))
}
Это приведет к тому, что пункты назначения попадут в стек, поэтому, когда вы нажмете кнопку «Назад», появится последний посещенный пункт назначения.
Секретным соусом было добавление идентификатора в навигационный график. Я использую панель навигации, но принцип тот же
Можем ли мы иметь единственный экземпляр фрагмента?
Я не уверен, что lib - это тот, кто заботится о создании экземпляра, но я нигде не вижу места, где мы могли бы это настроить: /
Но на самом деле я не ищу этого, я хочу вернуть тот экземпляр, на котором мы в последний раз ходили
Это нормально работает с кнопкой возврата. Но если пользователь нажимает на нижние вкладки, он не восстанавливает ранее открытый дочерний фрагмент этой вкладки (если он доступен). Он просто открывает новый момент (родительского) фрагмента каждый раз, когда пользователь нажимает на нижние вкладки. Таким образом, этот способ приведет к сбиванию с толку / разочарованию пользователей при многократной навигации с использованием нижних вкладок. Опасная реализация
они не используют единый контейнер для фрагментов. Каждая страница поддерживает свою заднюю стопку. кроме того, переключаться между вкладками очень быстро. либо это окно просмотра, либо у них есть его собственная реализация
Если кнопка возврата не работает (то есть, если приложение закрывается вместо перехода к первому фрагменту), убедитесь, что все идентификаторы настроены правильно (мне пришлось добавить несколько '+' в '@id' (как в @ + id) и что NavHostFragment настроен с помощью app: defaultNavHost = true
Я думал, что в BottomNavigationView max может быть только три вкладки. Разве это больше не так?
Максимального числа нет, но в правилах материального дизайна указано, что у вас должно быть не более 5 вкладок.
@LeviMoreira Не могли бы вы предоставить для этого демонстрационную ссылку?
Я хочу воссоздать фрагмент снова, когда пользователь переключает нижние вкладки, как этого добиться. В том смысле, что я не хочу снова вызывать API-интерфейс каждый раз, когда пользователь переключает фрагмент
@kondal есть ли у вас какое-нибудь решение, чтобы не воссоздавать фрагменты снова и снова?
@Niroshan, вы нашли решение своей проблемы, помогите мне, если вы нашли
@ OK200 Не официальный ответ! Но мы можем преодолеть это, расширив FragmentNavigator по умолчанию. Посмотрите этот простой пример github.com/STAR-ZERO/navigation-keep-fragment-sample! (Взгляните на класс KeepStateNavigator). ** Не забудьте заменить ключевое слово 'фрагмент' на 'keep_state_fragment' (или аннотацию ключевого слова, используемую в вашем расширенном классе), используемую в вашем nav_graph (xml)
Решите проблему с воссозданием вкладок, указав это в вашем BaseFragment: (Это должно быть рекомендуемое решение, но я забыл, где я его читал) private var previousLoadedView: View? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { if (previousLoadedView == null) { previousLoadedView = inflater.inflate(layoutId, container, false) } else { (previousLoadedView?.parent as? ViewGroup)?.removeAllViews() } return previousLoadedView }
@Niroshan В принципе, существует официальный обходной путь, пока проблема не будет устранена. Вы можете найти это здесь github.com/android/architecture-components-samples/blob/master /…
Я создал подобное приложение (все еще не опубликованное в PlayStore) с такой же навигацией, возможно, его реализация отличается от того, что делает Google в своих приложениях, но функциональность такая же.
структура включает в себя у меня есть основное действие, в котором я переключаю его содержимое, показывая / скрывая фрагменты, используя:
public void switchTo(final Fragment fragment, final String tag /*Each fragment should have a different Tag*/) {
// We compare if the current stack is the current fragment we try to show
if (fragment == getSupportFragmentManager().getPrimaryNavigationFragment()) {
return;
}
// We need to hide the current showing fragment (primary fragment)
final Fragment currentShowingFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
final FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (currentShowingFragment != null) {
fragmentTransaction.hide(currentShowingFragment);
}
// We try to find that fragment if it was already added before
final Fragment alreadyAddedFragment = getSupportFragmentManager().findFragmentByTag(tag);
if (alreadyAddedFragment != null) {
// Since its already added before we just set it as primary navigation and show it again
fragmentTransaction.setPrimaryNavigationFragment(alreadyAddedFragment);
fragmentTransaction.show(alreadyAddedFragment);
} else {
// We add the new fragment and then show it
fragmentTransaction.add(containerId, fragment, tag);
fragmentTransaction.show(fragment);
// We set it as the primary navigation to support back stack and back navigation
fragmentTransaction.setPrimaryNavigationFragment(fragment);
}
fragmentTransaction.commit();
}
Вы должны установить навигацию хоста, как показано ниже xml:
<LinearLayout 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"
android:orientation = "vertical">
<android.support.v7.widget.Toolbar
android:id = "@+id/toolbar"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:background = "@color/colorPrimary" />
<fragment
android:id = "@+id/navigation_host_fragment"
android:name = "androidx.navigation.fragment.NavHostFragment"
android:layout_width = "match_parent"
android:layout_height = "0dp"
android:layout_weight = "1"
app:defaultNavHost = "true"
app:navGraph = "@navigation/nav_graph" />
<android.support.design.widget.BottomNavigationView
android:id = "@+id/bottom_navigation_view"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
app:itemIconTint = "@drawable/color_state_list"
app:itemTextColor = "@drawable/color_state_list"
app:menu = "@menu/menu_bottom_navigation" />
</LinearLayout>
Настройка с помощью контроллера навигации:
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_host_fragment);
NavigationUI.setupWithNavController(bottomNavigationView, navHostFragment.getNavController());
menu_bottom_navigation.xml:
<?xml version = "1.0" encoding = "utf-8"?>
<menu xmlns:android = "http://schemas.android.com/apk/res/android">
<item
android:id = "@id/tab1" // Id of navigation graph
android:icon = "@mipmap/ic_launcher"
android:title = "@string/tab1" />
<item
android:id = "@id/tab2" // Id of navigation graph
android:icon = "@mipmap/ic_launcher"
android:title = "@string/tab2" />
<item
android:id = "@id/tab3" // Id of navigation graph
android:icon = "@mipmap/ic_launcher"
android:title = "@string/tab3" />
</menu>
nav_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/nav_graph"
app:startDestination = "@id/tab1">
<fragment
android:id = "@+id/tab1"
android:name = "com.navigationsample.Tab1Fragment"
android:label = "@string/tab1"
tools:layout = "@layout/fragment_tab_1" />
<fragment
android:id = "@+id/tab2"
android:name = "com.navigationsample.Tab2Fragment"
android:label = "@string/tab2"
tools:layout = "@layout/fragment_tab_2"/>
<fragment
android:id = "@+id/tab3"
android:name = "com.simform.navigationsample.Tab3Fragment"
android:label = "@string/tab3"
tools:layout = "@layout/fragment_tab_3"/>
</navigation>
При установке того же идентификатора «nav_graph» на «menu_bottom_navigation» будет обрабатываться щелчок нижней навигации.
Вы можете обработать обратное действие, используя свойство popUpTo в теге action.

Можете ли вы уточнить использование popUpTo?
Свойство @BincyBaby popUpTo помогает вам вернуться к определенному фрагменту при обратном нажатии.
@SANAT, а как настроить popUpTo на фрагмент, который сразу же нажимался раньше? Например, если вы были в frag1, перешли на frag2, а затем на frag3, нажатие назад должно вернуться к frag2. Если вы были в frag1 и сразу перешли на frag3, обратное нажатие вернет вас на frag1. popUpTo, кажется, позволяет вам выбрать только один фрагмент для возврата, независимо от пути пользователя.
Без сохранения порядка стека назад, кнопка «Назад» переходит на 1-ю вкладку, исключая 2-ю вкладку. Мало того, не сохраняется состояние фрагмента, вместо этого создается новый экземпляр при каждом щелчке ButtomNavigationItem.
@Farid может контролировать, чтобы не создавать новый экземпляр каждый раз при выборе.
@Farid, знаете ли вы, как это разрешить? Это вызывает у меня проблему.
@SuyashDixit, честно говоря, я не пошел с этим шаблоном, но вы можете сделать следующее. Создавайте свои фрагменты и show/hide их вместо add/replace. Если это непонятно, я отправлю фрагмент кода в качестве ответа.
есть идеи, можем ли мы использовать это в моей демонстрации stackoverflow.com/questions/63052712/…
что если я нажму кнопку назад? фрагмент будет перемещаться вверх, но нижняя панель навигации не будет обновлена.
Если у вас есть bottomNavigationView с 3 элементами, соответствующими 3 Fragment: FragmentA, FragmentB и FragmentC, где FragmentA - это startDestination на вашем навигационном графике, то, когда вы находитесь на FragmentB или FragmentC и нажимаете назад, вы будете перенаправлены на FragmentA, это поведение, рекомендованное Google и реализованное по умолчанию.
Однако, если вы хотите изменить это поведение, вам нужно будет либо использовать ViewPager, как было предложено некоторыми другими ответами, либо вручную обрабатывать фрагменты backStack и обратные транзакции самостоятельно, что в некотором смысле подорвало бы использование Navigation компонент в целом-.
Но YouTube, Instagram, Saavn ведут себя иначе.
Правда, нет правильного или неправильного способа сделать это, это просто о том, что Google поддерживает по умолчанию (и, следовательно, рекомендует) и каковы ваши потребности. Если эти два не совпадают, вам нужно обойти это.
Но проблема в том, что если вы используете JetPack Navigation, backStack будет пустым. Очевидно, JetPack ничего не добавляет в задний стек при обработке щелчков BottomNavigation.
Во-первых, позвольте мне прояснить, как Youtube и Instagram обрабатывают фрагментную навигацию.
Ни один из других ответов выше не решает всех этих проблем с использованием навигации на реактивном ранце.
Навигация JetPack не имеет стандартного способа сделать это, способ, который я нашел более простым, - это разделить навигационный xml-график на один для каждого нижнего элемента навигации, самостоятельно обработать задний стек между элементами навигации с помощью действия FragmentManager и использовать JetPack NavController для обработки внутренней навигации между корневым и детальным фрагментами (его реализация использует стек childFragmentManager).
Предположим, у вас в папке navigation есть 3 xmls:
res/navigation/
navigation_feed.xml
navigation_explore.xml
navigation_profile.xml
Иди назначения в xmls навигации должны совпадать с идентификаторами меню bottomNavigationBar. Кроме того, для каждого xml установите app:startDestination на фрагмент, который вы хотите использовать в качестве корня элемента навигации.
Создайте класс BottomNavController.kt:
class BottomNavController(
val context: Context,
@IdRes val containerId: Int,
@IdRes val appStartDestinationId: Int
) {
private val navigationBackStack = BackStack.of(appStartDestinationId)
lateinit var activity: Activity
lateinit var fragmentManager: FragmentManager
private var listener: OnNavigationItemChanged? = null
private var navGraphProvider: NavGraphProvider? = null
interface OnNavigationItemChanged {
fun onItemChanged(itemId: Int)
}
interface NavGraphProvider {
@NavigationRes
fun getNavGraphId(itemId: Int): Int
}
init {
var ctx = context
while (ctx is ContextWrapper) {
if (ctx is Activity) {
activity = ctx
fragmentManager = (activity as FragmentActivity).supportFragmentManager
break
}
ctx = ctx.baseContext
}
}
fun setOnItemNavigationChanged(listener: (itemId: Int) -> Unit) {
this.listener = object : OnNavigationItemChanged {
override fun onItemChanged(itemId: Int) {
listener.invoke(itemId)
}
}
}
fun setNavGraphProvider(provider: NavGraphProvider) {
navGraphProvider = provider
}
fun onNavigationItemReselected(item: MenuItem) {
// If the user press a second time the navigation button, we pop the back stack to the root
activity.findNavController(containerId).popBackStack(item.itemId, false)
}
fun onNavigationItemSelected(itemId: Int = navigationBackStack.last()): Boolean {
// Replace fragment representing a navigation item
val fragment = fragmentManager.findFragmentByTag(itemId.toString())
?: NavHostFragment.create(navGraphProvider?.getNavGraphId(itemId)
?: throw RuntimeException("You need to set up a NavGraphProvider with " +
"BottomNavController#setNavGraphProvider")
)
fragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.nav_default_enter_anim,
R.anim.nav_default_exit_anim,
R.anim.nav_default_pop_enter_anim,
R.anim.nav_default_pop_exit_anim
)
.replace(containerId, fragment, itemId.toString())
.addToBackStack(null)
.commit()
// Add to back stack
navigationBackStack.moveLast(itemId)
listener?.onItemChanged(itemId)
return true
}
fun onBackPressed() {
val childFragmentManager = fragmentManager.findFragmentById(containerId)!!
.childFragmentManager
when {
// We should always try to go back on the child fragment manager stack before going to
// the navigation stack. It's important to use the child fragment manager instead of the
// NavController because if the user change tabs super fast commit of the
// supportFragmentManager may mess up with the NavController child fragment manager back
// stack
childFragmentManager.popBackStackImmediate() -> {
}
// Fragment back stack is empty so try to go back on the navigation stack
navigationBackStack.size > 1 -> {
// Remove last item from back stack
navigationBackStack.removeLast()
// Update the container with new fragment
onNavigationItemSelected()
}
// If the stack has only one and it's not the navigation home we should
// ensure that the application always leave from startDestination
navigationBackStack.last() != appStartDestinationId -> {
navigationBackStack.removeLast()
navigationBackStack.add(0, appStartDestinationId)
onNavigationItemSelected()
}
// Navigation stack is empty, so finish the activity
else -> activity.finish()
}
}
private class BackStack : ArrayList<Int>() {
companion object {
fun of(vararg elements: Int): BackStack {
val b = BackStack()
b.addAll(elements.toTypedArray())
return b
}
}
fun removeLast() = removeAt(size - 1)
fun moveLast(item: Int) {
remove(item)
add(item)
}
}
}
// Convenience extension to set up the navigation
fun BottomNavigationView.setUpNavigation(bottomNavController: BottomNavController, onReselect: ((menuItem: MenuItem) -> Unit)? = null) {
setOnNavigationItemSelectedListener {
bottomNavController.onNavigationItemSelected(it.itemId)
}
setOnNavigationItemReselectedListener {
bottomNavController.onNavigationItemReselected(it)
onReselect?.invoke(it)
}
bottomNavController.setOnItemNavigationChanged { itemId ->
menu.findItem(itemId).isChecked = true
}
}
Сделайте свой макет main.xml следующим образом:
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width = "match_parent"
android:layout_height = "match_parent">
<FrameLayout
android:id = "@+id/container"
android:layout_width = "match_parent"
android:layout_height = "0dp"
app:layout_constraintBottom_toTopOf = "@id/bottomNavigationView"
app:layout_constraintTop_toTopOf = "parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id = "@+id/bottomNavigationView"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:layout_marginStart = "0dp"
android:layout_marginEnd = "0dp"
app:layout_constraintBottom_toBottomOf = "parent"
app:menu = "@menu/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
Используйте в своей деятельности так:
class MainActivity : AppCompatActivity(),
BottomNavController.NavGraphProvider {
private val navController by lazy(LazyThreadSafetyMode.NONE) {
Navigation.findNavController(this, R.id.container)
}
private val bottomNavController by lazy(LazyThreadSafetyMode.NONE) {
BottomNavController(this, R.id.container, R.id.navigation_feed)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
bottomNavController.setNavGraphProvider(this)
bottomNavigationView.setUpNavigation(bottomNavController)
if (savedInstanceState == null) bottomNavController
.onNavigationItemSelected()
// do your things...
}
override fun getNavGraphId(itemId: Int) = when (itemId) {
R.id.navigation_feed -> R.navigation.navigation_feed
R.id.navigation_explore -> R.navigation.navigation_explore
R.id.navigation_profile -> R.navigation.navigation_profile
else -> R.navigation.navigation_feed
}
override fun onSupportNavigateUp(): Boolean = navController
.navigateUp()
override fun onBackPressed() = bottomNavController.onBackPressed()
}
это решение выглядит хорошо, но есть некоторые вещи, которые я заметил: <FrameLayout /> должен быть NavHostFragment, каждый график имеет собственное домашнее значение по умолчанию, поэтому выполнение этого if (savedInstanceState == null) bottomNavController .onNavigationItemSelected() будет запускать фрагмент два раза, он не сохраняет состояния для фрагментов.
Идея сохраненного состояния экземпляра позволяет избежать создания фрагмента дважды. Я не могу это проверить, потому что в итоге я расширил NavController и создал собственный навигатор исключительно для NavHostFragment, добавив его в этот NavController (я назвал NavHostFragmentNavController). Затем я создаю граф с именем navigation_main.xml с элементами <nav-fragment>, каждый из которых представляет собой нижний элемент навигации. Новые реализации больше, но в использовании довольно просто. В коде все еще есть небольшие ошибки, которые я еще не исправил. Я выложу, когда исправлю.
да, я думаю, что на данный момент расширение NavController - это разумное решение, пока Google не выпустит образец.
Разве здесь не следует передавать пункт назначения в качестве последнего параметра вместо R.id.navigation_feed? private val bottomNavController by lazy(LazyThreadSafetyMode.NONE) { BottomNavController(this, R.id.container, R.id.navigation_feed) }
@WWJD, R.id.navigation_feed - это пункт назначения. Я назвал идентификатор графа тем же именем, что и начальный пункт назначения, поэтому у R.navigation.navigation_feed есть пункт назначения R.id.navigation_feed.
@AllanVeloso, это идеально подходит для меня. Отличное решение, я просто удалил NavigationExtension.kt из демонстрации Google, добавил весь ваш код и отлично работает. Я только что внес некоторые изменения в код, потому что я использую AHBottomNavigation, но работает так же. Для меня это было бы реальным решением сделать многостадийную навигацию с новой системой навигации.
Извините за шум, я только что улучшил этот код, добавив «fragmentManager.addOnBackStackChangedListener» в инициализацию контроллера, чтобы вы могли добавить «OnDestinationChangedListener». Таким образом, вы всегда будете знать, в каком фрагменте вы находитесь, от контроллера. Таким образом, вы можете внести некоторые обновления в пользовательский интерфейс Activity в случае необходимости. Напишите мне, если вам нужно обновить код. Еще раз спасибо за эту ветку! Теперь у меня отлично работает.
@jfcogato Чтобы отслеживать изменение пункта назначения, вы также можете расширить MutableLiveData. Использование было бы очень простым: DestinationLiveData(navController).observe(this, Observer { dest -> // do things }). Он также автоматически обрабатывает методы добавления и удаления слушателя. Прямо сейчас я пытаюсь разработать более полную библиотеку, которая переопределяет реализацию Jetpack NavController с этим поведением Instagram / youtube, но я все еще исправляю некоторые ошибки.
@AllanVeloso уверен, что это будет еще один способ получить это. Выглядит более чистым кодом, чем мой :) Буду ждать библиотеку! возможно, я смогу обновить все, что я сделал с вашим. Кстати, вы действительно спасли мне день, это решение отлично работает! и я думаю, что весь мой проект будет работать с этой навигационной системой сейчас и навсегда! :)
@AllanVeloso onNavigationItemReselected Не работает. Я имею в виду, что popBackStack всегда возвращает false. В остальном все работает как шарм.
@AllanVeloso Не могли бы вы посмотреть или помочь в этом?
@DushyantSuthar: реализация библиотеки навигации арки Android изменилась, и теперь popBackStack (), на мой взгляд, имеет довольно странное поведение (по мнению команды Android). Вы можете попробовать заменить .popBackStack () на .navigate (navController.currentDestination.parent) или что-то подобное и проверить, работает ли он.
Короткий и хороший код на Kotlin для соединения нижних элементов навигации с фрагментами внутри графа навигации:
val navControl = findNavController( R.id.nav_host_frag_main)
bottomNavigationView?.setupWithNavController(navControl)
* Просто учтите: идентификаторы и фрагменты нижней навигации внутри графа навигации должны иметь одинаковый идентификатор. Также благодаря хорошему объяснению из ответа @sanat
вам также следует скрыть стрелки «вверх» на прямых дочерних элементах BNV: setupActionBarWithNavController (navController, AppBarConfiguration.Builder (bottomNavigationView.menu) .build ())
Лучшее решение - это решение, предоставленное командой Google в его репо, кнопка «Назад» по-прежнему отправляет вас обратно к первой кнопке, но остальное поведение его «нормальное» ... Похоже, что Google по-прежнему не предлагает хорошего решения, даже когда они используют его (YouTube, Google Фото и т. д.), они сказали, что androidx может помочь, но похоже, что мы просто идем и находим обходной путь для обычных вещей.
Вот ссылка на Google Repo, где они используют nav. снизу с навигационным графом для каждой кнопки. https://github.com/android/architecture-components-samples/blob/master/NavigationAdvancedSample/app/src/main/java/com/example/android/navigationadvancedsample/NavigationExtensions.kt скопируйте этот файл в свой проект и посмотрите, как он реализован в их проекте. Для поведения кнопки возврата вы можете создать собственный стек, а onBackpressed просто перемещаться по этому стеку.
Официальных решений не нашел, но использую свой путь
Сначала я создаю стек для фрагментов ручки
needToAddToBackStack : Boolen = true
private lateinit var fragmentBackStack: Stack<Int>
fragmentBackStack = Stack()
И в
navController.addOnDestinationChangedListener { _, destination, _ ->
if (needToAddToBackStack) {
fragmentBackStack.add(destination.id)
}
needToAddToBackStack = true
}
и обработайте кнопку возврата
override fun onBackPressed() {
if (::fragmentBackStack.isInitialized && fragmentBackStack.size > 1) {
fragmentBackStack.pop()
val fragmentId = fragmentBackStack.lastElement()
needToAddToBackStack = false
navController.navigate(fragmentId)
} else {
if (::fragmentBackStack.isInitialized && fragmentBackStack.size == 1) {
finish()
} else {
super.onBackPressed()
}
}
Он отлично работает с обычной навигацией, но есть одна проблема при навигации с использованием BottomNavigationView. Например, скажем, у меня есть BottomNavigation с тремя вкладками с уважаемыми фрагментами A, B, C. Теперь мой путь навигации - от фрагмента A до B (щелкните вкладку B), от B до D (это еще один фрагмент, который открывается при нажатии кнопки из B), от D до E (другой фрагмент открывается нажатием кнопки с D) и, наконец, от E до C (при нажатии на вкладку C); оттуда, когда я нажимаю назад, он фрагментирует E, но показывает текущую выбранную вкладку C (в идеале она должна отображать вкладку B). Есть ли способ исправить это?
Прочитав ваш вопрос, я снова проверил документ Google. И я увидел, что они предоставили решение, позволяющее улучшить работу интерфейса навигации с BottomNavigationView. Итак, я создал туториал для всех, кому он нужен, как и мне. Для текстовой версии: https://nhatvm.com/how-to-use-navigationui-with-bottomnavigation-in-android/ А для версии youtube: https://thewikihow.com/video_2uxILvBbkyY
это практическое руководство по использованию пользовательского интерфейса навигации с нижним навигационным представлением, которое не помогает решить эту проблему!
В навигации с помощью реактивного ранца вам нужно внести изменения только в один xml-файл графа навигации для управления навигацией, обработкой бэкстэков, пользовательской анимацией, передачей аргументов между фрагментами.
Если вы хотите просто вернуться к предыдущему фрагменту,
<action
android:id = "@+id/action_deleteEmployeeFragment_to_employeesListFragment2"
app:destination = "@id/employeesListFragment"/>
btn_cancel.setOnClickListener {
it.findNavController().popBackStack()
}
Если вы хотите очистить все бэкстэки и перейти к новому фрагменту
<action
android:id = "@+id/action_deleteEmployeeFragment_to_employeesListFragment2"
app:destination = "@id/employeesListFragment"
app:popUpTo = "@id/employeesListFragment"
app:popUpToInclusive = "true"
app:launchSingleTop = "true" />
btn_submit.setOnClickListener {
it.findNavController().navigate(DeleteEmployeeFragmentDirections.actionDeleteEmployeeFragmentToEmployeesListFragment2())
}
Для получения дополнительной информации: Пример навигации на реактивном ранце
Ключевым моментом для создания правильного заднего стека, который хранит состояние, является наличие NavHostFragment, у которого есть childFragmentManager и их собственный задний стек. Именно это и делает файл расширения расширенного примера компонента "Навигация".
/**
* Manages the various graphs needed for a [BottomNavigationView].
*
* This sample is a workaround until the Navigation Component supports multiple back stacks.
*/
fun BottomNavigationView.setupWithNavController(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
containerId: Int,
intent: Intent
): LiveData<NavController> {
// Map of tags
val graphIdToTagMap = SparseArray<String>()
// Result. Mutable live data with the selected controlled
val selectedNavController = MutableLiveData<NavController>()
var firstFragmentGraphId = 0
// First create a NavHostFragment for each NavGraph ID
navGraphIds.forEachIndexed { index, navGraphId ->
val fragmentTag = getFragmentTag(index)
// Find or create the Navigation host fragment
val navHostFragment = obtainNavHostFragment(
fragmentManager,
fragmentTag,
navGraphId,
containerId
)
// Obtain its id
val graphId = navHostFragment.navController.graph.id
if (index == 0) {
firstFragmentGraphId = graphId
}
// Save to the map
graphIdToTagMap[graphId] = fragmentTag
// Attach or detach nav host fragment depending on whether it's the selected item.
if (this.selectedItemId == graphId) {
// Update livedata with the selected graph
selectedNavController.value = navHostFragment.navController
attachNavHostFragment(fragmentManager, navHostFragment, index == 0)
} else {
detachNavHostFragment(fragmentManager, navHostFragment)
}
}
// Now connect selecting an item with swapping Fragments
var selectedItemTag = graphIdToTagMap[this.selectedItemId]
val firstFragmentTag = graphIdToTagMap[firstFragmentGraphId]
var isOnFirstFragment = selectedItemTag == firstFragmentTag
// When a navigation item is selected
setOnNavigationItemSelectedListener { item ->
// Don't do anything if the state is state has already been saved.
if (fragmentManager.isStateSaved) {
false
} else {
val newlySelectedItemTag = graphIdToTagMap[item.itemId]
if (selectedItemTag != newlySelectedItemTag) {
// Pop everything above the first fragment (the "fixed start destination")
fragmentManager.popBackStack(
firstFragmentTag,
FragmentManager.POP_BACK_STACK_INCLUSIVE
)
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
as NavHostFragment
// Exclude the first fragment tag because it's always in the back stack.
if (firstFragmentTag != newlySelectedItemTag) {
// Commit a transaction that cleans the back stack and adds the first fragment
// to it, creating the fixed started destination.
fragmentManager.beginTransaction()
.attach(selectedFragment)
.setPrimaryNavigationFragment(selectedFragment)
.apply {
// Detach all other Fragments
graphIdToTagMap.forEach { _, fragmentTagIter ->
if (fragmentTagIter != newlySelectedItemTag) {
detach(fragmentManager.findFragmentByTag(firstFragmentTag)!!)
}
}
}
.addToBackStack(firstFragmentTag)
.setCustomAnimations(
R.anim.nav_default_enter_anim,
R.anim.nav_default_exit_anim,
R.anim.nav_default_pop_enter_anim,
R.anim.nav_default_pop_exit_anim
)
.setReorderingAllowed(true)
.commit()
}
selectedItemTag = newlySelectedItemTag
isOnFirstFragment = selectedItemTag == firstFragmentTag
selectedNavController.value = selectedFragment.navController
true
} else {
false
}
}
}
// Optional: on item reselected, pop back stack to the destination of the graph
setupItemReselected(graphIdToTagMap, fragmentManager)
// Handle deep link
setupDeepLinks(navGraphIds, fragmentManager, containerId, intent)
// Finally, ensure that we update our BottomNavigationView when the back stack changes
fragmentManager.addOnBackStackChangedListener {
if (!isOnFirstFragment && !fragmentManager.isOnBackStack(firstFragmentTag)) {
this.selectedItemId = firstFragmentGraphId
}
// Reset the graph if the currentDestination is not valid (happens when the back
// stack is popped after using the back button).
selectedNavController.value?.let { controller ->
if (controller.currentDestination == null) {
controller.navigate(controller.graph.id)
}
}
}
return selectedNavController
}
private fun BottomNavigationView.setupDeepLinks(
navGraphIds: List<Int>,
fragmentManager: FragmentManager,
containerId: Int,
intent: Intent
) {
navGraphIds.forEachIndexed { index, navGraphId ->
val fragmentTag = getFragmentTag(index)
// Find or create the Navigation host fragment
val navHostFragment = obtainNavHostFragment(
fragmentManager,
fragmentTag,
navGraphId,
containerId
)
// Handle Intent
if (navHostFragment.navController.handleDeepLink(intent)
&& selectedItemId != navHostFragment.navController.graph.id
) {
this.selectedItemId = navHostFragment.navController.graph.id
}
}
}
private fun BottomNavigationView.setupItemReselected(
graphIdToTagMap: SparseArray<String>,
fragmentManager: FragmentManager
) {
setOnNavigationItemReselectedListener { item ->
val newlySelectedItemTag = graphIdToTagMap[item.itemId]
val selectedFragment = fragmentManager.findFragmentByTag(newlySelectedItemTag)
as NavHostFragment
val navController = selectedFragment.navController
// Pop the back stack to the start destination of the current navController graph
navController.popBackStack(
navController.graph.startDestination, false
)
}
}
private fun detachNavHostFragment(
fragmentManager: FragmentManager,
navHostFragment: NavHostFragment
) {
fragmentManager.beginTransaction()
.detach(navHostFragment)
.commitNow()
}
private fun attachNavHostFragment(
fragmentManager: FragmentManager,
navHostFragment: NavHostFragment,
isPrimaryNavFragment: Boolean
) {
fragmentManager.beginTransaction()
.attach(navHostFragment)
.apply {
if (isPrimaryNavFragment) {
setPrimaryNavigationFragment(navHostFragment)
}
}
.commitNow()
}
private fun obtainNavHostFragment(
fragmentManager: FragmentManager,
fragmentTag: String,
navGraphId: Int,
containerId: Int
): NavHostFragment {
// If the Nav Host fragment exists, return it
val existingFragment = fragmentManager.findFragmentByTag(fragmentTag) as NavHostFragment?
existingFragment?.let { return it }
// Otherwise, create it and return it.
val navHostFragment = NavHostFragment.create(navGraphId)
fragmentManager.beginTransaction()
.add(containerId, navHostFragment, fragmentTag)
.commitNow()
return navHostFragment
}
private fun FragmentManager.isOnBackStack(backStackName: String): Boolean {
val backStackCount = backStackEntryCount
for (index in 0 until backStackCount) {
if (getBackStackEntryAt(index).name == backStackName) {
return true
}
}
return false
}
private fun getFragmentTag(index: Int) = "bottomNavigation#$index"
Важной частью здесь является получение NavHostFragment, если он не существует в заднем стеке с указанной выше функцией, и добавление его в задний стек. commitNow синхронен в отличие от commit
приватное развлечение GetNavHostFragment ( fragmentManager: FragmentManager, fragmentTag: строка, navGraphId: Int, containerId: Int ): NavHostFragment { // Если фрагмент Nav Host существует, вернуть его val existingFragment = fragmentManager.findFragmentByTag (fragmentTag) как NavHostFragment? existingFragment? .let {вернуть его}
// Otherwise, create it and return it.
val navHostFragment = NavHostFragment.create(navGraphId)
fragmentManager.beginTransaction()
.add(containerId, navHostFragment, fragmentTag)
.commitNow()
return navHostFragment
}
Я построил один, используя расширение NavigationExtension выше, которое выглядит так
с вложенной навигацией.
Графики навигации похожи, поэтому добавляю только один
nav_graph_home.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"
android:id = "@+id/nav_graph_home"
app:startDestination = "@id/homeFragment1">
<fragment
android:id = "@+id/homeFragment1"
android:name = "com.smarttoolfactory.tutorial5_3navigationui_bottomnavigation_nestednavigation.blankfragment.HomeFragment1"
android:label = "HomeFragment1"
tools:layout = "@layout/fragment_home1">
<action
android:id = "@+id/action_homeFragment1_to_homeFragment2"
app:destination = "@id/homeFragment2" />
</fragment>
<fragment
android:id = "@+id/homeFragment2"
android:name = "com.smarttoolfactory.tutorial5_3navigationui_bottomnavigation_nestednavigation.blankfragment.HomeFragment2"
android:label = "HomeFragment2"
tools:layout = "@layout/fragment_home2">
<action
android:id = "@+id/action_homeFragment2_to_homeFragment3"
app:destination = "@id/homeFragment3" />
</fragment>
<fragment
android:id = "@+id/homeFragment3"
android:name = "com.smarttoolfactory.tutorial5_3navigationui_bottomnavigation_nestednavigation.blankfragment.HomeFragment3"
android:label = "HomeFragment3"
tools:layout = "@layout/fragment_home3" >
<action
android:id = "@+id/action_homeFragment3_to_homeFragment1"
app:destination = "@id/homeFragment1"
app:popUpTo = "@id/homeFragment1"
app:popUpToInclusive = "true" />
</fragment>
</navigation>
Меню для нижней навигации
menu_bottom_nav.xml
<?xml version = "1.0" encoding = "utf-8"?>
<menu xmlns:android = "http://schemas.android.com/apk/res/android">
<item
android:id = "@+id/nav_graph_home"
android:icon = "@drawable/ic_baseline_home_24"
android:title = "Home"/>
<item
android:id = "@+id/nav_graph_dashboard"
android:icon = "@drawable/ic_baseline_dashboard_24"
android:title = "Dashboard"/>
<item
android:id = "@+id/nav_graph_notification"
android:icon = "@drawable/ic_baseline_notifications_24"
android:title = "Notification"/>
</menu>
Макет для MainActivity, содержащий FragmentContainerView и BottomNavigationView
activiy_main.xml
<?xml version = "1.0" encoding = "utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id = "@+id/nav_host_container"
android:layout_width = "0dp"
android:layout_height = "0dp"
app:layout_constraintBottom_toTopOf = "@+id/bottom_nav"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintRight_toRightOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id = "@+id/bottom_nav"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
app:layout_constraintBottom_toBottomOf = "parent"
app:menu = "@menu/menu_bottom_nav" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var currentNavController: LiveData<NavController>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportFragmentManager.addOnBackStackChangedListener {
val backStackEntryCount = supportFragmentManager.backStackEntryCount
val fragments = supportFragmentManager.fragments
val fragmentCount = fragments.size
Toast.makeText(
this,
"MainActivity backStackEntryCount: $backStackEntryCount, fragmentCount: $fragmentCount, fragments: $fragments",
Toast.LENGTH_SHORT
).show()
}
if (savedInstanceState == null) {
setupBottomNavigationBar()
} // Else, need to wait for onRestoreInstanceState
}
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
super.onRestoreInstanceState(savedInstanceState)
// Now that BottomNavigationBar has restored its instance state
// and its selectedItemId, we can proceed with setting up the
// BottomNavigationBar with Navigation
setupBottomNavigationBar()
}
/**
* Called on first creation and when restoring state.
*/
private fun setupBottomNavigationBar() {
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
val navGraphIds = listOf(
R.navigation.nav_graph_home,
R.navigation.nav_graph_dashboard,
R.navigation.nav_graph_notification
)
// Setup the bottom navigation view with a list of navigation graphs
val controller = bottomNavigationView.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.nav_host_container,
intent = intent
)
// Whenever the selected controller changes, setup the action bar.
controller.observe(this, Observer { navController ->
setupActionBarWithNavController(navController)
})
currentNavController = controller
}
override fun onSupportNavigateUp(): Boolean {
return currentNavController?.value?.navigateUp() ?: false
}
}
Макеты и классы фрагментов - это простые классы, поэтому я пропустил их. Вы можете проверить полный образец i built или Репозиторий Google, чтобы изучить расширение для расширенной навигации или другие примеры.
ты хоть представляешь это stackoverflow.com/questions/63052712/…
@SunilChaudhary, да, если вы проверяете репо для компонентов навигации или функцию расширения выше или по ссылке, вы можете увидеть, как это работает. Примеры в это репо показывают, как это можно сделать разными способами.
Первоначальный ответ здесь: https://stackoverflow.com/a/63645978/8956093
В Jetpack Navigation Componenet, если вы хотите выполнить какую-либо операцию, когда фрагмент выталкивается, вам необходимо переопределить следующие функции.
Добавьте OnBackPressedCallback во фрагмент, чтобы запустить специальную операцию при нажатии кнопки «Назад» на панели навигации системы внизу.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
//perform your operation and call navigateUp
findNavController().navigateUp()
}
}
requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback)
}
Добавьте onOptionsItemMenu во фрагмент для обработки нажатия стрелки назад в верхнем левом углу приложения.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
//perform your operation and call navigateUp
findNavController().navigateUp()
return true
}
return super.onOptionsItemSelected(item)
}
Если нет специального кода для запуска при нажатии back на фрагменте хоста, используйте onSupportNavigateUp в Activity.
override fun onSupportNavigateUp(): Boolean {
if (navController.navigateUp() == false){
//navigateUp() returns false if there are no more fragments to pop
onBackPressed()
}
return navController.navigateUp()
}
Обратите внимание, что onSupportNavigateUp () не вызывается, если фрагмент содержит onOptionsItemSelected ()
В версии 2.4.0 навигационного пакета он наконец-то официально поддерживается!
https://developer.android.com/jetpack/androidx/releases/navigation#version_240_2
Мало того: после загрузки библиотеки навигации в эту версию эта функция - поведение по умолчанию. И в качестве примечания, теперь это поведение по умолчанию включает в себя то, что фрагменты не воссоздаются при переходе между ними, это казалось чем-то весьма востребованным.
Привет, @BincyBaby, мне нужно то же самое, у тебя есть какие-нибудь решения?