Так должен выглядеть замещенный метод onNavigationItemSelected
:
override fun onNavigationItemSelected(item: MenuItem): Boolean
{
drawerLayout.close()
// this part checks if current fragment is the same as destination
return if (findNavController(R.id.navHostFragment).currentDestination?.id != item.itemId)
{
val builder = NavOptions.Builder()
.setLaunchSingleTop(true)
.setEnterAnim(R.anim.enter_left_to_right)
.setExitAnim(R.anim.exit_right_to_left)
.setPopEnterAnim(R.anim.popenter_right_to_left)
.setPopExitAnim(R.anim.popexit_left_to_right)
// this part set proper pop up destination to prevent "looping" fragments
if (item.order and Menu.CATEGORY_SECONDARY == 0)
{
var startDestination: NavDestination? =
findNavController(R.id.navHostFragment).graph
while (startDestination is NavGraph)
{
val parent = startDestination
startDestination = parent.findNode(parent.startDestination)
}
builder.setPopUpTo(
startDestination!!.id,
false
)
}
val options = builder.build()
return try
{
findNavController(R.id.navHostFragment).navigate(item.itemId, null, options)
true
}
catch (e: IllegalArgumentException) // couldn't find destination, do nothing
{
false
}
}
else
{
false
}
}
Этот метод предотвращает переход к текущим выбранным фрагментам. Поэтому, когда пользователь находится в Fragment A
и в панели навигации снова выбирает Fragment A
, ничего не произойдет, панель навигации просто скроется.
Этот метод также предотвращает "зацикливание" фрагментов , в стеке может быть только один фрагмент, который был выбран в панели навигации или меню панели инструментов. Например, в панели навигации есть Fragment A
и Fragment B
. Пользователь находится в Fragment Home
, затем от go до Fragment A
и рядом с Fragment B
. Если пользователь нажимает кнопку "Назад", приложение go вернется к Fragment Home
, а не к Fragment A
. Кроме того, вместо поиска startDestination
через некоторое время l oop можно использовать R.id.homeFragment
. Если кто-то хочет разрешить "зацикливание" фрагментов, просто удалите эту часть кода.
Я протестировал это решение, и, похоже, оно работает хорошо, но, конечно, может быть что-то, что работает не так, как должно.
Если кому-то нужна простая анимация с постепенным проявлением / исчезновением и вертикальным перемещением:
R.anim.enter_left_to_right
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@integer/fragment_anim_time"
android:fromXDelta="-100%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="0%" />
<alpha
android:duration="@integer/fragment_anim_time"
android:fromAlpha="0.5"
android:toAlpha="1" />
</set>
R.anim.exit_right_to_left
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@integer/fragment_anim_time"
android:fromXDelta="0%"
android:fromYDelta="0%"
android:toXDelta="100%"
android:toYDelta="0%" />
<alpha
android:duration="@integer/fragment_anim_time"
android:fromAlpha="1"
android:toAlpha="0.5" />
</set>
R.anim.popenter_right_to_left
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@integer/fragment_anim_time"
android:fromXDelta="100%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="0%" />
<alpha
android:duration="@integer/fragment_anim_time"
android:fromAlpha="0.5"
android:toAlpha="1" />
</set>
R.anim.popexit_left_to_right
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@integer/fragment_anim_time"
android:fromXDelta="0%"
android:fromYDelta="0%"
android:toXDelta="-100%"
android:toYDelta="0%" />
<alpha
android:duration="@integer/fragment_anim_time"
android:fromAlpha="1"
android:toAlpha="0.5" />
</set>
res / значения / целые числа. xml
<integer name="fragment_anim_time">250</integer>