我有2个动作
Action1
<action
android:id="@+id/actionBaseFragmentToAskForLocation"
app:destination="@+id/introAskForLocationFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
Action2
<action
android:id="@+id/actionIntroAskLocationToLogin"
app:destination="@id/loginFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_right"
app:popExitAnim="@anim/fade_out"
app:popUpTo="@+id/app_main_navigation" />
我想要的是当第二个动作被触发时,我想清除后堆栈并仅将loginFragment设置为保留在堆栈中。
一个问题是当我执行Action2时,“ slide_out_right”作为退出动画执行
我了解,如果我们从堆栈中弹出片段,则将触发action1的“ popExitAnim”,而不是action2的“ exitAnim”。
但是我想知道如何使片段执行slide_out_left动画以退出并同时将其弹出堆栈。
答案 0 :(得分:2)
由于NavOptions
由将抽屉绑定到导航图上使用的便捷方法在内部进行处理,因此这很难解决。我最初使用设置菜单和onOptionsItemSelected
测试了此解决方案,但基本思想也应在这里使用。
首先,请确保您的菜单项ID与导航片段的ID相符:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
...
<item android:id="@+id/example_id" ... />
</menu>
<navigation xmlns:android="http://schemas.android.com/apk/res/android" ... >
...
<fragment android:id="@+id/example_id" ... />
</navigation>
现在,不要在NavHost活动中为connecting the drawer to your NavController使用现成的方法实现NavigationView.OnNavigationItemSelectedListener
并像下面这样覆盖方法onNavigationItemSelected
:
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
NavHost navHost = Navigation.findNavController(this, R.id.your_nav_host_fragment);
return NavigationUI.onNavDestinationSelected(item, navHost);
}
这会将选择内容转发为图形中的导航。将your_nav_host_fragment
替换为设置了app:defaultNavHost="true"
的片段ID。
您会注意到,尽管这有效,但仍默认为幻灯片动画。这是因为NavigationUI
call internally creates its own NavOptions
具有以下设置:
NavOptions.Builder builder = new NavOptions.Builder()
.setLaunchSingleTop(true)
.setEnterAnim(R.anim.nav_default_enter_anim)
.setExitAnim(R.anim.nav_default_exit_anim)
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
.setPopExitAnim(R.anim.nav_default_pop_exit_anim);
不幸的是,该方法尚未使用NavOptions.Builder
作为参数,但是您可以基于Android源代码创建实用程序类来模仿该功能:
public class NavigationUIHelper {
public static boolean onNavDestinationSelected(@NonNull MenuItem item,
@NonNull NavController navController,
@NonNull NavOptions.Builder builder) {
if ((item.getOrder() & Menu.CATEGORY_SECONDARY) == 0) {
NavDestination destination = findStartDestination(navController.getGraph());
builder.setPopUpTo(destination.getId(), false);
}
NavOptions options = builder.build();
try {
navController.navigate(item.getItemId(), null, options);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
// Need to copy this private method as well
private static NavDestination findStartDestination(@NonNull NavGraph graph) {
NavDestination startDestination = graph;
while (startDestination instanceof NavGraph) {
NavGraph parent = (NavGraph) startDestination;
startDestination = parent.findNode(parent.getStartDestination());
}
return startDestination;
}
}
最后,您现在可以在活动中将对NavigationUI的调用替换为NavigationUIHelper中实现的调用:
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
NavHost navHost = Navigation.findNavController(this, R.id.your_nav_host_fragment);
NavOptions.Builder builder = new NavOptions.Builder()
.setLaunchSingleTop(true)
.setEnterAnim(R.anim.custom_enter)
.setExitAnim(R.anim.custom_exit)
.setPopEnterAnim(R.anim.custom_pop_enter)
.setPopExitAnim(R.anim.custom_pop_exit);
return NavigationUIHelper.onNavDestinationSelected(item, navHost, builder);
}
这应该允许您根据自己的喜好更改抽屉过渡动画,而不必替换导航组件。
答案 1 :(得分:2)
我最终在调用onCreateAnimation
的片段中重载了navigate
。此示例显示如何通过ID导航嵌套的导航图并有条件地替换 pop 退出动画(或popExitAnim
)。
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
val navController = findNavController()
val graph = navController.graph.findNode(R.id.onboardingGraph) as NavGraph
val dest = graph.findNode(R.id.confirmationFragment)
if (!enter && dest != null && navController.currentDestination?.id == dest.id) {
return AnimationUtils.loadAnimation(requireContext(), R.anim.slide_out_left)
}
return super.onCreateAnimation(transit, enter, nextAnim)
}
请注意,这种特殊情况部分是由于幻灯片动画的方向性所致。