使用导航抽屉或工具栏菜单动画化片段过渡
Animate fragment transitions with using Navigation drawer or Toolbar menu
我有一个导航抽屉和工具栏菜单,我可以从中转到另一个片段。我用它来导航:
override fun onNavigationItemSelected(item: MenuItem): Boolean
{
drawerLayout.close()
return NavigationUI.onNavDestinationSelected(
item,
findNavController(R.id.navHostFragment)
)
}
如何在切换片段时添加自定义动画?
是Answer your own question
。我遇到过这个问题,但找不到任何对我来说 100% 有效的答案,所以也许这会对某些人有所帮助。
重写的方法 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
,然后转到 Fragment A
并在 Fragment B
旁边。如果用户单击后退按钮,应用程序将返回到 Fragment Home
,而不是 Fragment A
。此外,可以使用 R.id.homeFragment
而不是在 while 循环中查找 startDestination
。如果有人想要允许“循环”片段,只需删除代码中的这一部分。
我已经测试了这个解决方案,它似乎运行良好,但当然也有可能无法正常工作。
如果有人想要带有淡入淡出 in/fade 和垂直平移的简单动画:
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/values/integers.xml
<integer name="fragment_anim_time">250</integer>
我有一个导航抽屉和工具栏菜单,我可以从中转到另一个片段。我用它来导航:
override fun onNavigationItemSelected(item: MenuItem): Boolean
{
drawerLayout.close()
return NavigationUI.onNavDestinationSelected(
item,
findNavController(R.id.navHostFragment)
)
}
如何在切换片段时添加自定义动画?
是Answer your own question
。我遇到过这个问题,但找不到任何对我来说 100% 有效的答案,所以也许这会对某些人有所帮助。
重写的方法 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
,然后转到Fragment A
并在Fragment B
旁边。如果用户单击后退按钮,应用程序将返回到Fragment Home
,而不是Fragment A
。此外,可以使用R.id.homeFragment
而不是在 while 循环中查找startDestination
。如果有人想要允许“循环”片段,只需删除代码中的这一部分。
我已经测试了这个解决方案,它似乎运行良好,但当然也有可能无法正常工作。
如果有人想要带有淡入淡出 in/fade 和垂直平移的简单动画:
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/values/integers.xml
<integer name="fragment_anim_time">250</integer>