使用导航组件动态设置工具栏标题

13

我想要动态设置工具栏标题,但我不知道是否可能。

假设我有一个项目列表,每次点击一个项目时都会打开一个新的片段,因此我试图为每个项目动态更改工具栏标题。

我尝试过:

it.findNavController().navigate(direction)
it.findNavController().currentDestination!!.label = someTitle

但它不起作用。

有一些相关的主题,例如:

如何使用导航架构组件在应用栏中设置标题

但它不能高效地解决我的问题,这只是一个解决方法。


这个回答解决了你的问题吗?使用AndroidX Navigation从Fragment动态更改ActionBar标题 - lcnicolau
@lcnicolau 是的,没错 - Ibrahim Ali
3个回答

28

Navigation 1.0.0-alpha08或更高版本开始,导航支持在标签中使用参数:

当与NavigationUI方法一起使用时,目标标签会自动将android:label中的{argName}实例替换为正确的参数b/80267266

因此,您可以将标签设置为android:label="{dynamicTitle}",然后在navigate调用中传入参数。由于您正在使用Safe Args,因此应向目标添加一个参数:

<fragment
    android:id="@+id/myFragment"
    android:name=".MyFragment"
    android:label="{dynamicTitle}">
  <argument
      android:name="dynamicTitle"
      app:argType="string"/>
</fragment>

在构建指令时,将您的动态标题传递:

val directions = YourDirections.actionToMyFragment(someTitle)
it.findNavController().navigate(directions)
当然,你可以自己监听导航事件,并使用自己的OnDestinationChangedListener来做任何你想做的事情,包括将标签设置为你想要的内容。没有必要使用NavigationUI,调用NavigationUI方法后添加的任何监听器都会覆盖它所设置的内容。

3
我发现这种方法存在问题,如果设备旋转(活动/视图被销毁),标题将被重置(变为空白)。请告诉我您是否能够复现。 - Joaquim Ley
@rguerra - 当然是的。如果您看到不同的情况,您应该提交一个问题。 - ianhanniballake
1
正确。但如果使用 destination.label,它会返回 {dynamicTitle}。 - rafaelasguerra
1
@rguerra - 如果您没有使用NavigationUI,那么您需要手动完成一些操作,这是完全可以预料的,并且在Navigation的所有版本中都是如此,无论是在引入此功能之前还是之后。如果您希望看到更多的NavigationUI助手函数公开用于自定义实现,请随时提交功能请求。 - ianhanniballake
@JoaquimLey 如果您通过编程方式指定工具栏标题 supportActionBar?.title = getString(R.string.app_name) 或在工具栏布局中使用xml指定 app:title="@string/app_name",则在旋转时标题将不会重置。 - Thomas W.
显示剩余4条评论

3

如果您正在传递自定义的Object作为参数,您可以使用navController.addOnDestinationChangedListener

navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
    @Override
    public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
        Log.i(TAG, "onDestinationChanged");
        switch (destination.getId()) {
            case R.id.mainFragment:
                updateToolbarAndBottomNavigation("Main Title", "Main Subtitle", View.VISIBLE);
                break;
            case R.id.shopFragment:
                updateToolbarAndBottomNavigation("custom title", null, View.VISIBLE);
                break;
            case R.id.shopcartFragment:
                StoreEntity store = (StoreEntity) arguments.get("storeEntity");
                Log.i(TAG, "onDestinationChanged: ShopCartFragment args: "+store.getName());
                updateToolbarAndBottomNavigation(store.getName(), null, View.GONE);
                break;
        }

    }
});

private void updateToolbarAndBottomNavigation(String title, String subtitle, int visibility) {
    getSupportActionBar().setTitle(title);
    getSupportActionBar().setSubtitle(subtitle);
    bottomNavigationView.setVisibility(visibility);
}

arguments.get()是从nav_graph.xml中的android:name获取的。

<fragment
        android:id="@+id/shopcartFragment"
        android:name="com.myapp.ShopcartFragment"
        tools:layout="@layout/fragment_shopcart" >
        <argument
            android:name="storeEntity" // GET ARGUMENTS NAME HERE
            app:argType="com.myapp.LocalDatabase.StoreEntity" />
    </fragment>

我希望它能帮助更多的人!


1
他们在问Kotlin。他们可能无法理解Java。 - hamthenormal

1
你可以添加一个方法来更新片段的标题,并在片段的 onStart() 方法中调用它。
fun updateToolbarTitle(title: String) {
    supportActionBar?.title = title
}

在您的 nav_graph.xml 中,移除导航标签上的 lable 属性,这样它就会变成这样。
<fragment
    android:id="@+id/myFragment"
    android:name=".MyFragment"/>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接