使用 AndroidX 导航的片段中的动态 ActionBar 标题
Dynamic ActionBar title from a Fragment using AndroidX Navigation
我正在使用来自 Android Jetpack 的新 Navigation 组件。
root Activity 设置非常简单:
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"
这样的技巧,但我觉得它会破坏 setupActionBarWithNavController()
为我所做的魔法。有什么方法可以动态更新 Action Bar 标题吗?
您可以在 activity 中添加 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"
}
}
}
另一种解决方案是使用 ViewModel 和 LiveData,将 viewmodel 附加到您的 activity 和片段,在 viewmodel
中添加一个 livedata 字段
val title = MutableLiveData<String>()
从你的 activity 观察这个字段,如果它被改变更新工具栏标题
viewModel?.title?.observe(this, Observer {
my_toolbar.title=it
})
从您想要的片段更改视图模型中的标题字段
viewModel?.title?.value="New title"
截至目前,Jetpack 导航架构组件不提供任何 "built in" 方法来执行此操作,您必须实现自己的 "custom" 方法来执行此操作。
现有的功能请求是获取添加到新 Jetpack 导航架构组件的目的地上的动态标签功能。如果您是因为 want/need 此功能而来到这里,请在此处为现有功能请求加注星标:
https://issuetracker.google.com/issues/80267266
在 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")
考虑到您的主机 activity 是 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
}
从 graph.xml 文件中删除标签
android:label="fragment_info"
如果您想从片段本身动态设置片段的标题,请使用老式方法
getActivity().setTitle("Your Title");
在尝试 activity 的标题时,它似乎覆盖了片段的标题。为了安全起见,你必须穿上 onResume
.
override fun onResume() {
super.onResume()
activity?.toolbar.title = "YOUR_TITLE_HERE"
}
对我有用!
注意: activity
中必须有工具栏小部件
在您的 activity 的 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>
从 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>
在这里,我们 <fragment>
的 android:label
属性有一个用大括号括起来的参数名称({title}
in "Title: {title}"
)。应用栏的标题将被设置为标签的值,{title}
替换为 title
参数的值。
如果您需要比这更复杂的东西——例如,您想通过 ID 查找模型并从中读取 属性——您将需要使用更多手动方法,例如概述的方法在这个问题的其他答案中。
好吧,现在导航 UI 支持此功能。现在 ActionBar
标题会动态变化。您只需将 ActionBar
设置为 NavController
.
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()
}
你可以去掉导航图中的android:label然后在onCreateView()
中写入
activity?.title="your title"
如果您在 Activity 中使用 setSupportActionBar 上的工具栏,并且您想在片段中更改其标题,那么下面的代码可能会对您有所帮助 ;)
(requireActivity() as MainActivity).toolbar.title = "Title here"
可以通过将 activity 转换为 AppCompatActivity
来更改片段中的标题。
Kotlin
(requireActivity() as AppCompatActivity).supportActionBar?.title = "Hello"
Java
((AppCompatActivity) requireActivity()).getSupportActionBar().setTitle("Hello");
如果您的标题是从串联字符串中收到的,例如:
ActionBar actionBar = ((AppCompatActivity)
requireActivity()).getSupportActionBar();
if(actionBar!=null)
actionBar.setTitle(count + "items");
根据以下解决方案,无需手动访问工具栏。
如果您要将模型传递到目标片段中。
然后你就可以按照下面的方式去做了。
覆盖模型中的 toString()
方法 class
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}"
将从模型 class.
的 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>
希望对您有所帮助。
基于@kaustubh-trivedi 的回答,如果您使用的是 MVVM(如 Android Studio FirstFragment/SecondFragment 示例):
KOTLIN 版本
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
}
JAVA版本
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
binding.toolbar.setTitle(destination.getLabel());
}
});
我正在使用来自 Android Jetpack 的新 Navigation 组件。
root Activity 设置非常简单:
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"
这样的技巧,但我觉得它会破坏 setupActionBarWithNavController()
为我所做的魔法。有什么方法可以动态更新 Action Bar 标题吗?
您可以在 activity 中添加 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"
}
}
}
另一种解决方案是使用 ViewModel 和 LiveData,将 viewmodel 附加到您的 activity 和片段,在 viewmodel
中添加一个 livedata 字段val title = MutableLiveData<String>()
从你的 activity 观察这个字段,如果它被改变更新工具栏标题
viewModel?.title?.observe(this, Observer {
my_toolbar.title=it
})
从您想要的片段更改视图模型中的标题字段
viewModel?.title?.value="New title"
截至目前,Jetpack 导航架构组件不提供任何 "built in" 方法来执行此操作,您必须实现自己的 "custom" 方法来执行此操作。
现有的功能请求是获取添加到新 Jetpack 导航架构组件的目的地上的动态标签功能。如果您是因为 want/need 此功能而来到这里,请在此处为现有功能请求加注星标: https://issuetracker.google.com/issues/80267266
在 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")
考虑到您的主机 activity 是 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
}
从 graph.xml 文件中删除标签
android:label="fragment_info"
如果您想从片段本身动态设置片段的标题,请使用老式方法
getActivity().setTitle("Your Title");
在尝试 activity 的标题时,它似乎覆盖了片段的标题。为了安全起见,你必须穿上 onResume
.
override fun onResume() {
super.onResume()
activity?.toolbar.title = "YOUR_TITLE_HERE"
}
对我有用!
注意: activity
中必须有工具栏小部件在您的 activity 的 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>
从 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>
在这里,我们 <fragment>
的 android:label
属性有一个用大括号括起来的参数名称({title}
in "Title: {title}"
)。应用栏的标题将被设置为标签的值,{title}
替换为 title
参数的值。
如果您需要比这更复杂的东西——例如,您想通过 ID 查找模型并从中读取 属性——您将需要使用更多手动方法,例如概述的方法在这个问题的其他答案中。
好吧,现在导航 UI 支持此功能。现在 ActionBar
标题会动态变化。您只需将 ActionBar
设置为 NavController
.
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()
}
你可以去掉导航图中的android:label然后在onCreateView()
中写入activity?.title="your title"
如果您在 Activity 中使用 setSupportActionBar 上的工具栏,并且您想在片段中更改其标题,那么下面的代码可能会对您有所帮助 ;)
(requireActivity() as MainActivity).toolbar.title = "Title here"
可以通过将 activity 转换为 AppCompatActivity
来更改片段中的标题。
Kotlin
(requireActivity() as AppCompatActivity).supportActionBar?.title = "Hello"
Java
((AppCompatActivity) requireActivity()).getSupportActionBar().setTitle("Hello");
如果您的标题是从串联字符串中收到的,例如:
ActionBar actionBar = ((AppCompatActivity)
requireActivity()).getSupportActionBar();
if(actionBar!=null)
actionBar.setTitle(count + "items");
根据以下解决方案,无需手动访问工具栏。
如果您要将模型传递到目标片段中。 然后你就可以按照下面的方式去做了。
覆盖模型中的 toString()
方法 class
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}"
将从模型 class.
<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>
希望对您有所帮助。
基于@kaustubh-trivedi 的回答,如果您使用的是 MVVM(如 Android Studio FirstFragment/SecondFragment 示例):
KOTLIN 版本
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
}
JAVA版本
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
binding.toolbar.setTitle(destination.getLabel());
}
});