Как программно изменить начальный пункт назначения навигационного графика [Jetpack]
По сути, у меня есть следующий график навигации:
Я хочу изменить свою начальную точку на навигационном графике на fragment 2
сразу после его достижения (во избежание возврата к fragment 1
при нажатии кнопки "назад" - как на заставке).
Это мой код:
navGraph = navController.getGraph();
navGraph.setStartDestination(R.id.fragment2);
navController.setGraph(navGraph);
Но, очевидно, он не работает и возвращается к fragment 1
после нажатия кнопки назад.
Я делаю это неправильно? Есть ли другое решение?
Ответы
Ответ 1
UPDATE:
Если у вас есть навигационный график, например:
<fragment
android:id="@+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
И вы хотите перейти ко второму фрагменту и сделать его корнем своего графика, укажите следующий NavOptions
:
NavOptions navOptions = new NavOptions.Builder()
.setPopUpTo(R.id.firstFragment, true)
.build();
И используйте их для навигации:
Navigation.findNavController(view).navigate(R.id.action_firstFragment_to_secondFragment, bundle, navOptions);
setPopUpTo(int destinationId, boolean inclusive)
- всплыть до заданного пункта назначения перед навигацией. При этом все несоответствующие назначения извлекаются из заднего стека, пока этот адресат не будет найден.
destinationId
- пункт назначения для всплывающего окна, очищающий все промежуточные пункты назначения.
inclusive
- true, чтобы извлекать заданное место назначения из заднего стека.
АЛЬТЕРНАТИВА:
<fragment
android:id="@+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:popUpTo="@+id/firstFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
А потом в вашем коде:
findNavController(fragment).navigate(
FirstFragmentDirections.actionFirstFragmentToSecondFragment())
Старый ответ
Устаревшее: атрибут clearTask
для действий и связанного API в NavOptions
устарел.
Источник: https://developer.android.com/jetpack/docs/release-notes
Если вы хотите изменить свой корневой фрагмент на fragment 2
(например, после нажатия кнопки "Назад" на fragment 2
вы выйдете из приложения), вам следует добавить следующий атрибут в action
или destination
:
app:clearTask="true"
Практически это выглядит следующим образом:
<fragment
android:id="@+id/firstFragment"
android:name="com.appname.package.FirstFragment"
android:label="fragment_first" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:clearTask="true" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.appname.package.SecondFragment"
android:label="fragment_second"/>
Я добавил app:clearTask="true"
к действию.
Теперь, когда вы выполняете переход от fragment 1
к fragment 2
, используйте следующий код:
Navigation.findNavController(view)
.navigate(R.id.action_firstFragment_to_secondFragment);
Ответ 2
Я нашел решение для этого, но это уродливо. Я предполагаю, что этого следовало ожидать с альфа-библиотекой, но я надеюсь, что Google будет упрощать/исправлять это, поскольку это довольно популярный шаблон навигации.
Решение Алексея не сработало для меня. Моя проблема заключалась в том, что у меня есть стрелки, показанные на моей панели действий, используя:
NavigationUI.setupActionBarWithNavController(this, navController)
Если бы я сделал это, как предлагает Алексей, у моего нового фрагмента начала была стрелка, указывающая на мой первоначальный фрагмент начала. Если бы я нажал эту стрелку вверх, мое приложение будет сортировать перезагрузку, переходя к себе (новый начальный фрагмент)
Вот код, необходимый для получения того, что я хотел:
- Фрагмент # 1 - это то, где мое приложение изначально начинается
- Я могу выполнить проверку Auth в фрагменте # 1, а затем программно изменить начало на фрагмент # 2.
- Как только во Фрагменте № 2 нет стрелки вверх, и нажатие кнопки "Назад" не приведет вас к фрагменту №1.
Вот код, который выполняет это. В моей деятельности onCreate:
// Setup the toolbar
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
// Configure the navigation
val navHost = nav_host_fragment as NavHostFragment
graph = navHost.navController
.navInflater.inflate(R.navigation.nav_graph)
graph.startDestination = R.id.welcomeFragment
// This seems to be a magical command. Not sure why it needed :(
navHost.navController.graph = graph
NavigationUI.setupActionBarWithNavController(this, navHost.navController)
а также:
fun makeHomeStart(){
graph.startDestination = R.id.homeFragment
}
Затем во Фрагменте №1 по Активному Искусству, по предложению Алексея:
override fun onActivityCreated(savedInstanceState: Bundle?) {
...
// Check for user authentication
if(sharedViewModel.isUserAuthenticated()) {
(activity as MainActivity).makeHomeStart() //<---- THIS is the key
val navOptions = NavOptions.Builder()
.setPopUpTo(R.id.welcomeFragment, true)
.build()
navController.navigate(R.id.action_welcomeFragment_to_homeFragment,null,navOptions)
} else {
navController.navigate(R.id.action_welcomeFragment_to_loginFragment)
}
}
Ключевым кодом является: (activity as MainActivity).makeHomeStart()
которая просто запускает метод в действии, который изменяет начало начала диаграмм. Я мог бы очистить это и превратить его в интерфейс, но я буду ждать Google и надеюсь, что они улучшат весь этот процесс. Метод setPopUpTo кажется мне плохо названным, и это не интуитивно понятно, что вы называете фрагмент, который вырезается из графика. Мне также странно, что они вносят эти изменения в navOptions. Я думаю, что navOptions будет относиться только к навигационному действию, к которому они подключены.
И я даже не знаю, что такое navHost.navController.graph = graph
, но без него вернутся стрелки вверх. :(
Я использую Navigation 1.0.0-alpha06.
Ответ 3
Вам не нужно вставлять всплеск фрагмент. Он может оставаться там до конца жизни вашего приложения. Что вы должны сделать, это с помощью экрана-заставки определить, какой следующий экран будет отображаться.
На картинке выше вы можете спросить в состоянии экрана-заставки, есть ли сохраненный LoginToken. Если он пуст, перейдите на экран входа в систему.
После завершения экрана входа в систему вы анализируете результат, сохраняете токен и переходите на домашний экран следующего фрагмента.
Когда кнопка "Назад" нажата на главном экране, вы отправите сообщение "Результат" на экран-заставку, в котором будет указано, что нужно завершить приложение.