使用AndroidX Navigation从Fragment动态ActionBar标题

时间:2018-05-30 07:55:25

标签: android android-jetpack android-architecture-navigation

我正在使用Android Jetpack中新的Navigation组件。

根活动设置非常简单:

Ascending

在导航图中定义Fragment的标题时效果很好。但对于一个片段,我想动态设置标题。

我尝试使用 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) val navController = findNavController(R.id.navigationFragment) setupActionBarWithNavController(navController) bottomNavigationView.setupWithNavController(navController) } ,但它什么也没做。

我当然可以使用像findNavController().currentDestination.label = "Hello world"这样的技巧,但我觉得它会打破(activity as? AppCompatActivity)?.supportActionBar?.title = "Hello world"对我的魔力。有没有办法动态更新动作栏标题?

14 个答案:

答案 0 :(得分:18)

1.0.0-alpha08开始,如果动态位是导航操作的参数,则可以让NavigationUI位动态设置标题...

因此,例如,在导航图中,您可能会遇到类似这样的情况:

  <fragment
    android:id="@+id/displayFragment"
    android:name="com.commonsware.jetpack.sampler.nav.DisplayFragment"
    android:label="Title: {title}" >
    <argument
      android:name="modelId"
      app:argType="string" />
    <argument
      android:name="title"
      app:argType="string" />
  </fragment>

在这里,我们的android:label的{​​{1}}属性用大括号({{1}中的<fragment>)包装了一个参数名称。然后,应用栏的标题将设置为该值标签的{title}替换为"Title: {title}"参数的值。

如果您需要比这更复杂的内容(例如,您想通过ID查找模型并从中读取属性),则需要使用更多手动方法,例如该问题的其他答案中概述的方法

答案 1 :(得分:6)

截至目前,Jetpack导航架构组件并未提供任何“内置”方式来执行此操作,您必须实现自己的“自定义”方法。

现有功能请求可以为添加到新Jetpack导航架构组件的目标上的动态标签获取功能。如果您在这里是因为您需要/需要此功能,请在此处标明现有功能请求: https://issuetracker.google.com/issues/80267266

答案 2 :(得分:6)

可以通过将活动强制转换为AppCompatActivity来更改片段中的标题。

科特林

(requireActivity() as AppCompatActivity).supportActionBar?.title = "Hello"

Java

((AppCompatActivity) requireActivity()).getSupportActionBar().setTitle("Hello");

答案 3 :(得分:5)

考虑到您的主机活动是MainActivity,只需将以下代码添加到MainActivity的onCreate乐趣中

            val navController = Navigation.findNavController(this, R.id.nav_host_fragment)

        //setting title according to fragment
        navController.addOnDestinationChangedListener { controller, destination, arguments ->
            toolbar.title = navController.currentDestination?.label
        }

答案 4 :(得分:3)

另一种解决方案是使用ViewModel和LiveData,将viewmodel附加到您的活动和片段,在viewmodel中添加一个livingata字段

val title = MutableLiveData<String>()

从您的活动中观察此字段,如果已更改,请更新工具栏标题

viewModel?.title?.observe(this, Observer { 
        my_toolbar.title=it
    })

从您想要的片段中更改viewmodel

中的标题字段
viewModel?.title?.value="New title"

答案 5 :(得分:3)

从graph.xml文件中删除标签

android:label="fragment_info"

如果要从片段本身动态设置片段的标题,请使用老式的方法

getActivity().setTitle("Your Title");

答案 6 :(得分:2)

如果您在Activity中的setSupportActionBar上使用工具栏,并且希望以碎片形式更改其标题,则下面的代码可能会帮助您;)

(requireActivity() as MainActivity).toolbar.title = "Title here"

答案 7 :(得分:1)

issue被修复之前,简单的侦听器对我有用:

/**
 * Temporary solution to dynamically change title of actionbar controlled by Navigation component
 * Should be removed as soon as the bug on Navigation will be fixed: (https://issuetracker.google.com/issues/80267266)
 */
interface TempToolbarTitleListener {
    fun updateTitle(title: String)
}

class MainActivity : AppCompatActivity(), TempToolbarTitleListener {

    ...

    override fun updateTitle(title: String) {
        binding.toolbar.title = title
    }
}

从片段更改标题:

(activity as TempToolbarTitleListener).updateTitle("custom title")

答案 8 :(得分:1)

如果您的标题是从连接字符串中接收的,例如:

ActionBar actionBar = ((AppCompatActivity) 
  requireActivity()).getSupportActionBar();
  
if(actionBar!=null)                   
   actionBar.setTitle(count + "items"); 

答案 9 :(得分:0)

尝试活动标题时,似乎会覆盖片段标题。为了安全起见,您必须戴上onResume

override fun onResume() {
    super.onResume()
    activity?.toolbar.title = "YOUR_TITLE_HERE"
}

对我有用!

注意:必须处于活动状态的工具栏小工具

在活动的xml中添加这样的工具栏

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </com.google.android.material.appbar.AppBarLayout>

    <!-- Other Widgets -->

</androidx.coordinatorlayout.widget.CoordinatorLayout>

答案 10 :(得分:0)

现在,导航UI支持此功能。现在,操作栏标题会动态更改。您只需要使用nav Controller设置操作栏即可。

private lateinit var appBarConfiguration: AppBarConfiguration

private lateinit var navController: NavController

override fun onCreate(savedInstanceState: Bundle?) {
    preferedTheme()
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(toolbar)
    navController = findNavController(R.id.nav_controller_fragment)
    appBarConfiguration = AppBarConfiguration(navController.graph)
    setupActionBarWithNavController(navController, appBarConfiguration)
}

并在导航图中设置操作栏标签:

<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/mobile_navigation"
        app:startDestination="@id/mainFragment">

<fragment android:id="@+id/mainFragment"
          android:name="com.cinderellaman.general.ui.fragments.MainFragment"
          android:label="General"
          tools:layout="@layout/main_fragment"/>

现在它还支持导航:

override fun onSupportNavigateUp(): Boolean {
    return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}

答案 11 :(得分:0)

您可以删除导航图中的 android:label ,然后在 onCreateView()

中编写
activity?.title="your title"

答案 12 :(得分:0)

根据以下解决方案,无需手动访问工具栏

如果您要将模型传递到目标片段中。 那么你就可以如下操作。

覆盖模型类中的 toString() 方法

data class UserModel(
    val userId: String = ""
    val firstName: String = "",
    val lastName: String = ""  
) {

    override fun toString(): String {
        return "$firstName $lastName"
    }
}

现在,在 nav_grap.xml 文件中,执行以下操作。 android:label="{UserData}" 将从模型类的 toString() 方法中获取标签。

<fragment
    android:id="@+id/messagesFragment"
    android:name="com.app.mydemoapp.ui.messages.MessagesFragment"
    android:label="{UserData}"
    tools:layout="@layout/fragment_messages">

    <argument
        android:name="UserData"
        app:argType="com.app.mydemoapp.model.UserModel" />

</fragment>

我希望这会有所帮助。

答案 13 :(得分:-1)

您可以在活动中添加addOnNavigatedListener,并根据当前目的地更改标题

 findNavController(nav_host_fragment).addOnNavigatedListener { controller, destination ->
        when(destination.id) {
            R.id.destination1 -> {
                my_toolbar.title= "Some title"
            }
            R.id.destination2 -> {
                my_toolbar.title= "Othertitle"

            }

    }
}