关于 android 导航架构组件的问题
Question about android navigation architecture component
我有一个问题。我正在使用 android 导航架构组件,使用带有单个 activity 的底部导航视图。如何让片段只打开一次?即使导致这个片段的按钮被点击了几次?
如何让片段只被添加到返回堆栈一次?
我创建了一个测试项目来试试
xml navigation_test
<?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
public class 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;
}
}
碎片 - 只是一片空白
您需要将片段声明为 "SingleTop"。
导航图编辑器视图右侧的菜单上有一个选项可以执行此操作,位于动画选项下方。
或者,您可以通过 NavOptions.Builder class 以编程方式设置它,使用下面 link 中详述的 setLaunchSingleTop(true) 方法:
所以您的 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);
根据 this issue,BottomNavigationView
提供 OnNavigationItemReselectedListener
优先于 NavigationUI
设置的 OnNavigationItemSelectedListener
:
bottomNavigationView.setOnNavigationItemReselectedListener(
new BottomNavigationView.OnNavigationReselectedListener() {
@Override
public void onNavigationItemReselected(MenuItem item) {
// By doing nothing, we ignore reselection events
}
});
NavigationView
不提供与 this other issue, so you'd want to copy the default behavior 相同的界面(请注意,它调用 NavigationUI.onNavDestinationSelected()
而不是直接调用 navigate()
,这与您的代码不同)和添加您自己的 isChecked()
检查以防止重新选择。
我有一个问题。我正在使用 android 导航架构组件,使用带有单个 activity 的底部导航视图。如何让片段只打开一次?即使导致这个片段的按钮被点击了几次? 如何让片段只被添加到返回堆栈一次? 我创建了一个测试项目来试试
xml navigation_test
<?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
public class 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;
}
}
碎片 - 只是一片空白
您需要将片段声明为 "SingleTop"。
导航图编辑器视图右侧的菜单上有一个选项可以执行此操作,位于动画选项下方。
或者,您可以通过 NavOptions.Builder class 以编程方式设置它,使用下面 link 中详述的 setLaunchSingleTop(true) 方法:
所以您的 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);
根据 this issue,BottomNavigationView
提供 OnNavigationItemReselectedListener
优先于 NavigationUI
设置的 OnNavigationItemSelectedListener
:
bottomNavigationView.setOnNavigationItemReselectedListener(
new BottomNavigationView.OnNavigationReselectedListener() {
@Override
public void onNavigationItemReselected(MenuItem item) {
// By doing nothing, we ignore reselection events
}
});
NavigationView
不提供与 this other issue, so you'd want to copy the default behavior 相同的界面(请注意,它调用 NavigationUI.onNavDestinationSelected()
而不是直接调用 navigate()
,这与您的代码不同)和添加您自己的 isChecked()
检查以防止重新选择。