Динамическое название 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"

            }

    }
}