Вы пытаетесь добавить модальное диалоговое окно к графику навигации в качестве обычного пункта назначения. NavController всегда будет показывать только один пункт назначения за раз, и они не будут сложены. Фрагмент удаляется из вида, когда NavController показывает другой. Он не предназначен для функционирования так, как вы хотите.
Вам необходимо создать AlertDialog
или DialogFragment
с вашим пользовательским интерфейсом. В показанном выше случае AlertDialog
уже будет достаточно. Вы можете добавить пользовательский вид к AlertDialog
, например так:
val dialog = AlertDialog.Builder(context)
.setView(R.layout.your_layout)
.show()
dialog.findViewById<View>(R.id.button).setOnClickListener {
// Do somehting
dialog.dismiss()
}
Это позволяет вам создать диалог с вашим пользовательским видом. Он будет работать так, как хотелось бы: щелчок по кнопке закрывает диалоговое окно, а также нажатие кнопки «Назад». Фон будет автоматически затемнен.
Диалог будет иметь форму по умолчанию, но вы можете следовать этому ответу, чтобы создать закругленные углы диалога, показанного в вашем вопросе.
Вы можете добавить анимацию к AlertDialog
с помощью анимации окна и пользовательского стиля, см. этот ответ .
Для более сложных видов, требующих жизненного цикла, следует использовать DialogFragment
(например, при отображении карты в диалоговом окне). Начиная с навигации 2.1.0-alpha03 <dialog>
пункты назначения поддерживаются. Это все еще в альфа / бета-версии.
Edit:
Если вы хотите очень точный контроль над анимацией, вы можете добавить вид к вашему макету следующим образом:
<FrameLayout>
<!-- Remove the defaultNavHost from this! -->
<fragment android:id="@+id/navHost" android:name="...NavHost" />
<FrameLayout android:id="@+id/dialog" android:background="#44000000" android:layout_width="match_parent" android:layout_height="match_parent">
<FrameLayout android:id="@+id/dialogContent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center">
<!-- Dialog contents -->
</FramyLayout>
</FrameLayout>
</FrameLayout>
Поскольку элемент находится после хоста nav в макете, он будет отображаться поверх него. Помните, что кнопки или другие элементы, имеющие набор свойств elevation
, могут отображаться поверх него.
Наконец, перезаписать свой onBackPressed()
в своей деятельности, чтобы восстановить поведение навигации:
override fun onBackPressed() {
val dialog = findViewById<View>(R.id.dialog)
val navController = (supportFragmentManager.findFragmentById(R.id.navHost) as NavHostFragment).navController
if (dialog.visibility == View.VISIBLE) {
hideDialog()
} else if(navController.popBackStack()) {
Log.i("MainActivity", "NavController handled back press")
} else {
super.onBackPressed()
}
}
private fun showDialog() {
findViewById<View>(R.id.dialog).visibility = View.VISIBLE
// Intro animation
}
private fun hideDialog() {
// Outro animation. Call the next line after the animation is done.
findViewById<View>(R.id.dialog).visibility = View.GONE
}
Это может быть то, что вы ищете, но я бы не рекомендовал это и работать вместо AlertDialog
или DialogFragment
.
Вы также можете использовать новое действие с прозрачным фоном для диалога и отключить анимацию для этого действия, чтобы вы могли вручную анимировать представления в действии. Деятельность может быть прозрачной на 100%.