导航组件——如何检查片段是新导航到还是弹回
Navigation component - how to check whether the fragment is newly navigated to vs. poped back to
使用导航组件时,导航到下一个片段很简单,弹回上一个片段也很简单。
Navigation.findNavController(v).navigate(R.id.action1);
/*vs*/
Navigation.findNavController(v).popBackStack();
如何在 onViewCreated()
中检查 startDestination / topLevel 目标片段是如何到达的?如果它被弹回到我想要 运行 与新导航到时不同的代码。
更新 感谢@Thracian 的建议:
我测试了:
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
Log.d("MAIN", "New destination ID: " + destination.getDisplayName());
}
});
但是returns结果是一样的,我是直接导航到一个fragment还是用popBack/navigateUp,所以无助于区分。
我测试了:
navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
navHostManager = navHostFragment.getChildFragmentManager();
navHostManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
int backStackEntryCount = navHostManager.getBackStackEntryCount();
int fragmentCount = navHostManager.getFragments().size();
Log.e("MAIN","backStackEntryCount: "+backStackEntryCount+", fragmentCount: " + fragmentCount);
}
});
不幸的是,我尝试解决这个问题的片段是 startDestination。因此,当我到达它时,backStackEntryCount
始终为 0,对于 navigateTo 和 navigateUp ...
对于我的其他顶级目的地,这也无法正常工作,因为它们总是显示 backStackEntryCount = 1
,与我如何到达它们无关。
您可以在 NavHostFragment 的 childManager 上使用 addOnBackstackChangeListener 并检查 backEntryCount 并将其与您存储在字段中的值进行比较。
对于 Activity 中的 FragmentContainerView,id 为 nav_host_fragment
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
你可以用
得到fragmentManager
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
val fragmentManager = navHostFragment?.childFragmentManager
并监听每个导航操作的 backStackEntryCount 变化。
fragmentManager?.addOnBackStackChangedListener {
val backStackEntryCount = fragmentManager.backStackEntryCount
val fragmentCount = fragmentManager.fragments.size
Toast.makeText(
applicationContext,
"backStackEntryCount: $backStackEntryCount, fragmentCount: $fragmentCount",
Toast.LENGTH_SHORT
).show()
}
您还可以查看当前目的地 ID,或者在需要时将它们存储在字段中。
findNavController(R.id.nav_host_fragment)
.addOnDestinationChangedListener { controller, destination, arguments ->
Toast.makeText(applicationContext, "Destination: ${destination.id}", Toast.LENGTH_SHORT)
.show()
}
要从任何片段访问这些数据,请使用 Activity 和片段通用的 ViewModel 并在 Activity 中设置值并在片段中监听。
我终于解决了问题。
感谢@Thracian 向我指出 navHostManager.getBackStackEntryCount()
和两个对调试至关重要的监听器。
我现在通过重写 onBackPressed()
:
解决了它
@Override
public void onBackPressed(){
if (navController.getPreviousBackStackEntry() == null ||
navController.getCurrentBackStackEntry() == null ||
navController.getCurrentBackStackEntry()
.getDestination().getId() == R.id.nav_dashboardFragment)
Log.d("MAIN", "back pressed on Dashboard");
else {
Log.d("MAIN", "Back pressed. Target: " + navController.getPreviousBackStackEntry().getDestination().getDisplayName());
Bundle args = new Bundle();
args.putInt(DashboardFragment.KEY_CANCEL_ANIMATION_ID, 1);
if (navHostManager.getBackStackEntryCount() > 1)
navController.navigateUp();
else
navController.navigate(R.id.nav_dashboardFragment, args,
new NavOptions.Builder().setPopUpTo(R.id.nav_dashboardFragment, true).build());
}
}
我先看看我是不是已经在出发地了。如果不是,我检查是否 getBackStackEntryCount() > 1
以了解下一个返回是否是起始目的地。如果下一个将是起始目的地,我不会调用 navigateUp()
而是直接 navigate() 带有一个参数告诉片段和最重要的 NavOptions
清除后台堆栈不加倍 startDestination返回堆栈(没有 NavOptions 无法工作)。
我在片段中添加了:
if (getArguments() != null && getArguments().get(KEY_CANCEL_ANIMATION_ID) != null) {
Log.d("DashV", "cancel animation detected");
motionLayout.setProgress(1);
}
在找到参数的情况下取消动画。
使用导航组件时,导航到下一个片段很简单,弹回上一个片段也很简单。
Navigation.findNavController(v).navigate(R.id.action1);
/*vs*/
Navigation.findNavController(v).popBackStack();
如何在 onViewCreated()
中检查 startDestination / topLevel 目标片段是如何到达的?如果它被弹回到我想要 运行 与新导航到时不同的代码。
更新 感谢@Thracian 的建议:
我测试了:
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
Log.d("MAIN", "New destination ID: " + destination.getDisplayName());
}
});
但是returns结果是一样的,我是直接导航到一个fragment还是用popBack/navigateUp,所以无助于区分。
我测试了:
navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
navHostManager = navHostFragment.getChildFragmentManager();
navHostManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
int backStackEntryCount = navHostManager.getBackStackEntryCount();
int fragmentCount = navHostManager.getFragments().size();
Log.e("MAIN","backStackEntryCount: "+backStackEntryCount+", fragmentCount: " + fragmentCount);
}
});
不幸的是,我尝试解决这个问题的片段是 startDestination。因此,当我到达它时,backStackEntryCount
始终为 0,对于 navigateTo 和 navigateUp ...
对于我的其他顶级目的地,这也无法正常工作,因为它们总是显示 backStackEntryCount = 1
,与我如何到达它们无关。
您可以在 NavHostFragment 的 childManager 上使用 addOnBackstackChangeListener 并检查 backEntryCount 并将其与您存储在字段中的值进行比较。
对于 Activity 中的 FragmentContainerView,id 为 nav_host_fragment
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
你可以用
得到fragmentManager
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
val fragmentManager = navHostFragment?.childFragmentManager
并监听每个导航操作的 backStackEntryCount 变化。
fragmentManager?.addOnBackStackChangedListener {
val backStackEntryCount = fragmentManager.backStackEntryCount
val fragmentCount = fragmentManager.fragments.size
Toast.makeText(
applicationContext,
"backStackEntryCount: $backStackEntryCount, fragmentCount: $fragmentCount",
Toast.LENGTH_SHORT
).show()
}
您还可以查看当前目的地 ID,或者在需要时将它们存储在字段中。
findNavController(R.id.nav_host_fragment)
.addOnDestinationChangedListener { controller, destination, arguments ->
Toast.makeText(applicationContext, "Destination: ${destination.id}", Toast.LENGTH_SHORT)
.show()
}
要从任何片段访问这些数据,请使用 Activity 和片段通用的 ViewModel 并在 Activity 中设置值并在片段中监听。
我终于解决了问题。
感谢@Thracian 向我指出 navHostManager.getBackStackEntryCount()
和两个对调试至关重要的监听器。
我现在通过重写 onBackPressed()
:
@Override
public void onBackPressed(){
if (navController.getPreviousBackStackEntry() == null ||
navController.getCurrentBackStackEntry() == null ||
navController.getCurrentBackStackEntry()
.getDestination().getId() == R.id.nav_dashboardFragment)
Log.d("MAIN", "back pressed on Dashboard");
else {
Log.d("MAIN", "Back pressed. Target: " + navController.getPreviousBackStackEntry().getDestination().getDisplayName());
Bundle args = new Bundle();
args.putInt(DashboardFragment.KEY_CANCEL_ANIMATION_ID, 1);
if (navHostManager.getBackStackEntryCount() > 1)
navController.navigateUp();
else
navController.navigate(R.id.nav_dashboardFragment, args,
new NavOptions.Builder().setPopUpTo(R.id.nav_dashboardFragment, true).build());
}
}
我先看看我是不是已经在出发地了。如果不是,我检查是否 getBackStackEntryCount() > 1
以了解下一个返回是否是起始目的地。如果下一个将是起始目的地,我不会调用 navigateUp()
而是直接 navigate() 带有一个参数告诉片段和最重要的 NavOptions
清除后台堆栈不加倍 startDestination返回堆栈(没有 NavOptions 无法工作)。
我在片段中添加了:
if (getArguments() != null && getArguments().get(KEY_CANCEL_ANIMATION_ID) != null) {
Log.d("DashV", "cancel animation detected");
motionLayout.setProgress(1);
}
在找到参数的情况下取消动画。