关于android导航架构组件的问题
Posted
技术标签:
【中文标题】关于android导航架构组件的问题【英文标题】:Question about android navigation architecture component 【发布时间】:2019-10-06 07:17:41 【问题描述】:我有一个问题。我正在使用 android 导航架构组件,使用带有单一活动的底部导航视图。如何使片段只打开一次?即使导致这个片段的按钮被点击了几次? 如何使片段只添加到回栈一次? 我创建了一个测试项目来试一试
xml 导航测试
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/test_nav"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="ru.artem_nr.navigation_test.FirstFragment"
android:label="fragment_first"
tools:layout="@layout/fragment_first" >
<action
android:id="@+id/action_firstFragment_to_secondFrag"
app:destination="@id/navigation"
app:launchSingleTop="true"
app:popUpTo="@+id/secondFrag"
app:popUpToInclusive="false" />
</fragment>
<navigation android:id="@+id/navigation"
app:startDestination="@id/secondFrag">
<fragment
android:id="@+id/secondFrag"
android:name="ru.artem_nr.navigation_test.SecondFrag"
android:label="fragment_second"
tools:layout="@layout/fragment_second" />
</navigation>
</navigation>
main_activity
公共类 MainActivity 扩展 AppCompatActivity 实现 NavigationView.OnNavigationItemSelectedListener
public Toolbar toolbar;
public DrawerLayout drawerLayout;
public NavController navController;
public NavigationView navigationView;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupNavigation();
private void setupNavigation()
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
drawerLayout = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.nav_view);
navController = Navigation.findNavController(this, R.id.garden_nav_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);
NavigationUI.setupWithNavController(navigationView, navController);
navigationView.setNavigationItemSelectedListener((NavigationView.OnNavigationItemSelectedListener) this);
@Override
public boolean onSupportNavigateUp()
return (boolean) NavigationUI.navigateUp(navController, drawerLayout);
@Override
public void onBackPressed()
if (drawerLayout.isDrawerOpen(GravityCompat.START))
drawerLayout.closeDrawer(GravityCompat.START);
else
super.onBackPressed();
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem)
menuItem.setChecked(true);
drawerLayout.closeDrawers();
int id = menuItem.getItemId();
switch (id)
case R.id.nav_home:
navController.navigate(R.id.navigation);
break;
return true;
片段 - 只是一个空白
【问题讨论】:
您的问题是底部导航,但您的代码使用了NavigationView
。您要使用的是哪个?是否正在尝试处理用户重新选择菜单中已选择的项目的情况?
我使用什么样的导航并不重要。在我的真实项目底部导航视图中,但正如我所说,我创建了一个测试项目。在抽屉布局中同样的问题。是的,你是对的,我正在努力处理它。如果用户重新选择某个片段,它将返回堆栈。如何解决?
【参考方案1】:
您需要将片段声明为“SingleTop”。
导航图编辑器视图右侧的菜单上有一个选项可以执行此操作,位于动画选项下方。
或者,您可以通过 NavOptions.Builder 类以编程方式设置它,使用 setLaunchSingleTop(true) 方法,详细信息如下链接所示:
https://developer.android.com/reference/kotlin/androidx/navigation/NavOptions.Builder#setLaunchSingleTop(kotlin.Boolean)
所以你的 on select 方法应该是这样的:
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem)
NavOptions.Builder builder = new NavOptions.Builder()
.setLaunchSingleTop(true);
NavOptions options = builder.build();
navController.navigate(item.getItemId(), null, options);
【讨论】:
您的意思是您尝试使用 NavOptions.Builder 以编程方式进行操作?如果您分享您的代码,我们或许可以为您发现问题 不,我是在界面中完成的。我创建了一个测试项目来试一试 以编程方式尝试? 是的,谢谢你的回答,但它并不适用于所有情况 你只能 setLaunchSingleTop() 用于动作,不能用于片段 - 所以你不能“将片段声明为 SingleTop”,尽管我希望你能这样做!【参考方案2】:根据this issue,BottomNavigationView
提供了一个优先于NavigationUI
设置的OnNavigationItemSelectedListener
的OnNavigationItemReselectedListener
:
bottomNavigationView.setOnNavigationItemReselectedListener(
new BottomNavigationView.OnNavigationReselectedListener()
@Override
public void onNavigationItemReselected(MenuItem item)
// By doing nothing, we ignore reselection events
);
NavigationView
不提供与this other issue 相同的接口,因此您需要copy the default behavior(请注意,它调用NavigationUI.onNavDestinationSelected()
而不仅仅是直接调用navigate()
,与您的代码不同)和为isChecked()
添加您自己的检查以防止重新选择。
【讨论】:
那么,目前平台没有这个问题的默认解决方案吗?如果我不理解 @АртемАртемов - 正确,每个组件完全相互独立。 我尝试使用 NavOptions.Builder 进行机器人导航视图。多次单击一个片段有帮助,但对于一种情况没有帮助,当我多次依次单击不同的图标时。创建大后栈,现在我看到了一种方法 - 如您所说,创建 isChecked(),但在大项目中这不是一个好的决定,因为我们需要为每个片段创建 isChecked() 方法。 您不应该在底部导航中设置OnNavigationItemSelectedListener
- 默认NavigationUI.setupWithNavController()
是正确的。
@ianhanniballake 我在使用抽屉布局时遇到了与全局操作类似的问题。我有 3 个***目的地(每个抽屉项目一个)。这些只是堆叠在一起。使用 launchSingleTop 没有任何作用。此外,进入/退出动画不适用于全局操作。这是一个错误吗?已知问题?围?如果没有,在哪里报告?以上是关于关于android导航架构组件的问题的主要内容,如果未能解决你的问题,请参考以下文章
关于 Android 移动团队的建设及未来架构的迭代升级思考