Как обрабатывать кнопку "Назад", когда она находится в начальном пункте назначения компонента навигации
Я начал работать с новым компонентом навигации, и я действительно копаю его! У меня действительно есть одна проблема - как я должен обрабатывать кнопку возврата, когда я нахожусь в начальной точке назначения графика?
Это код, который я использую сейчас:
findNavController(this, R.id.my_nav_host_fragment)
.navigateUp()
Когда я где-нибудь на своем графике, он отлично работает, он отправляет меня обратно, но когда я в самом начале - приложение вылетает, поскольку бэкстек пуст.
Это все имеет смысл для меня, я просто не уверен, как справиться с этим.
Хотя я могу проверить, совпадает ли идентификатор текущего фрагмента с тем, который, как я знаю, является корнем графа, я ищу более элегантное решение, например, какой-нибудь булевый флаг более или менее, текущее местоположение на графике исходное местоположение или нет.
Идеи?
5 ответов
У меня был похожий сценарий, в котором я хотел завершить упражнение, когда находился в пункте назначения начала, и выполнить обычное 'navigateUp', когда я был дальше вниз по навигационному графику. Я решил это с помощью простой функции расширения:
fun NavController.navigateUpOrFinish(activity: AppCompatActivity): Boolean {
return if (navigateUp()) {
true
} else {
activity.finish()
true
}
}
И затем назовите это как:
override fun onSupportNavigateUp() =
findNavController(R.id.nav_fragment).navigateUpOrFinish(this)
Однако я не смог использовать NavigationUI, так как это скрывало стрелку назад, когда я был в пункте назначения. Так что вместо:
NavigationUI.setupActionBarWithNavController(this, controller)
Я вручную управлял значком дома:
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_navigation_back)
Override onBackPressed
в своей деятельности и проверьте, является ли текущий пункт назначения начальным или нет.
Практически это выглядит так:
@Override
public void onBackPressed() {
if (Navigation.findNavController(this,R.id.nav_host_fragment)
.getCurrentDestination().getId() == R.id.your_start_destination) {
// handle back button the way you want here
return;
}
super.onBackPressed();
}
Вы не должны переопределять "onBackPressed", вы должны переопределить "onSupportNavigateUp" и поместить туда
findNavController(this, R.id.my_nav_host_fragment)
.navigateUp()
Из официальной документации:вы также перезапишите AppCompatActivity.onSupportNavigateUp() и вызовете NavController.navigateUp
https://developer.android.com/topic/libraries/architecture/navigation/navigation-implementing
В 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()
Так как моя кнопка "Назад" работает правильно, и при использовании NavController.navigateUp() произошел сбой при запуске кнопки "Назад". Я изменил этот код на что-то вроде этого. Другой возможностью будет просто проверить, является ли currentDestination == startDestination.id, но я хочу закрыть Activity и вернуться к другой Activity.
override fun onSupportNavigateUp() : Boolean {
//return findNavController(R.id.wizard_nav_host_fragment).navigateUp()
onBackPressed()
return true
}
/** in your activity **/
private boolean doubleBackToExitPressedOnce = false;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onBackPressed() {
int start = Navigation.findNavController(this, R.id.nav_host_fragment).getCurrentDestination().getId();
if (start == R.id.nav_home) {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(MainActivity.this, "Press back again to exits", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, 2000);
} else {
super.onBackPressed();
}
}
Если вы имеете в виду начало своего "корневого" навигационного графика (просто если у вас есть вложенные навигационные графики), то вам вообще не нужно показывать кнопку вверх, по крайней мере, в соответствии с принципами навигации.
Just call this in your back button Onclick
requireActivity().finish()