Динамическое название ActionBar из фрагмента с использованием AndroidX Navigation
Я использую новый компонент навигации от Android Jetpack.
Настройка корневых действий довольно проста:
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()
для меня. Есть ли способ динамически обновить заголовок панели действий?
Ответы
Ответ 1
Начиная с 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
для нашего <fragment>
имеет имя аргумента, заключенное в фигурные скобки ({title}
в "Title: {title}"
. В качестве заголовка панели приложения будет установлено значение метки с {title}
заменяется значением аргумента title
.
Если вам нужно что-то более сложное, чем это - например, вы хотите посмотреть модель по ID и прочитать свойство из нее - вам нужно будет использовать больше ручных подходов, таких как описанные в других ответах на этот вопрос.
Ответ 2
На данный момент компоненты Jetpack Navigation Architecture не предоставляют никакого "встроенного" способа сделать это, и вам придется реализовать свой собственный "пользовательский" метод для этого.
Существует существующий запрос функции для получения функциональности для динамических меток на местах назначения, добавленных к новым компонентам архитектуры навигации Jetpack. Если вы находитесь здесь, потому что хотите/нуждаетесь в этой функции, отметьте существующий запрос функции здесь: https://issuetracker.google.com/issues/80267266
Ответ 3
Принимая во внимание, что ваша деятельность хоста - MainActivity
, просто добавьте следующий код в MainActivity
onCreate
fun
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
Другим решением является использование ViewModel и LiveData, прикрепление viewmodel к вашей активности и фрагментам, добавление живого поля внутри viewmodel
val title = MutableLiveData<String>()
Из вашей активности наблюдайте это поле, и если оно изменено, обновите заголовок панели инструментов
viewModel?.title?.observe(this, Observer {
my_toolbar.title=it
})
Из желаемого фрагмента измените поле заголовка внутри модели просмотра
viewModel?.title?.value="New title"
Ответ 5
Удалить метку из файла graph.xml
android:label="fragment_info"
и использовать подход старой школы, если вы хотите динамически установить заголовок фрагмента из самого фрагмента
getActivity().setTitle("Your Title");
Ответ 6
Теперь интерфейс навигации поддерживает эту функцию. Теперь заголовок 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()
}
Ответ 7
Пока проблема не будет решена, для меня работает простой слушатель:
/**
* 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
При попытке использовать заголовок действия он перезаписывает заголовок фрагмента. Находясь на безопасной стороне, вы должны надеть 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>
Ответ 9
Вы можете удалить android: метку на графике навигации, а затем написать в onCreateView()
activity?.title="your title"
Ответ 10
Если вы используете панель инструментов для setSupportActionBar в Activity и хотите изменить ее заголовок в frgament, то приведенный ниже код может вам помочь;)
(requireActivity() as MainActivity).toolbar.title = "Title here"
Ответ 11
Вы можете добавить 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"
}
}
}