从片段更改MaterialToolbar标题 – Kotlin

huangapple go评论52阅读模式
英文:

Change MaterialToolbar title from Fragment - Kotlin

问题

I have implemented a MaterialToolbar and I want to change the title and functionality of the buttons, depending on which fragment is active. But I've been trying for two days and I can't get access to the toolbar from the fragment.

It doesn't work with any option:

  • activity?.actionBar?.title
  • (activity as AppCompatActivity).supportActionBar?.title

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/materialToolbar"
            style="@style/Widget.MaterialComponents.Toolbar.Primary"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:navigationIcon="@drawable/ic_menu" />

        <fragment
            android:id="@+id/fragmentContainer"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:defaultNavHost="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/materialToolbar"
            app:navGraph="@navigation/nav_graph" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@color/primary_ultra_light"
        app:headerLayout="@layout/header_menu_drawer"
        app:menu="@menu/menu_drawer" />

</androidx.drawerlayout.widget.DrawerLayout>

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setSupportActionBar(binding.materialToolbar)
        supportActionBar?.title = "Test"
    }
}

HomeFragment.kt

class HomeFragment: Fragment() {
    private lateinit var binding: HomeFragmentBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        activity?.actionBar?.title = "Home 1" /* actionBar == null */
         
        /* supportActionBar == null */
        (activity as AppCompatActivity).supportActionBar?.title = "Home 2"
    }
}

Result of the code that does not comply with the expected

The idea is to remove the top block of the fragment (Calculators) and use the Toolbar (Test). For this I need to be able to adapt the toolbar for each fragment.

  • Possible solution

So far I have solved it with a ViewModel observer. I don't know if it's a correct solution, but it works. Any comment is welcome, both to confirm that it is a valid solution and if it is not.

ToolbarVM.kt

class ToolbarVM(app: Application) : AndroidViewModel(app) {
    
    private val _title = MutableLiveData<String>()
    var title: LiveData<String> = _title
    
    fun setTitle(newTitle: String){
        _title.value = newTitle
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val toolbarVm: ToolbarVM by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setSupportActionBar(binding.materialToolbar)

        val titleObserver = Observer<String> { newTitle ->
            binding.materialToolbar.title = newTitle
        }

        toolbarVm.title.observe(this, titleObserver)
    }
}

HomeFragment

/* You have to instantiate the ToolbarVm and call the setTitle() method */
private lateinit var toolbarVm: ToolbarVM
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    toolbarVm = activity?.let { ViewModelProvider(it)[ToolbarVM::class.java] }!!
}

// Call the method where necessary
toolbarVm.setTitle("Calculators")
英文:

I have implemented a MaterialToolbar and I want to change the title and functionality of the buttons, depending on which fragment is active. But I've been trying for two days and I can't get access to toolbar from fragment.

It doesn't work with any option:

  • activity?.actionBar?.title
  • (activity as AppCompatActivity).supportActionBar?.title

activity_main.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.drawerlayout.widget.DrawerLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.view.MainActivity&quot;&gt;

    &lt;androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;&gt;

        &lt;com.google.android.material.appbar.MaterialToolbar
            android:id=&quot;@+id/materialToolbar&quot;
            style=&quot;@style/Widget.MaterialComponents.Toolbar.Primary&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;?attr/actionBarSize&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:navigationIcon=&quot;@drawable/ic_menu&quot; /&gt;

        &lt;fragment
            android:id=&quot;@+id/fragmentContainer&quot;
            android:name=&quot;androidx.navigation.fragment.NavHostFragment&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;0dp&quot;
            app:defaultNavHost=&quot;true&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/materialToolbar&quot;
            app:navGraph=&quot;@navigation/nav_graph&quot; /&gt;
    &lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;
    
    &lt;com.google.android.material.navigation.NavigationView
        android:id=&quot;@+id/navigationView&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;match_parent&quot;
        android:layout_gravity=&quot;start&quot;
        android:background=&quot;@color/primary_ultra_light&quot;
        app:headerLayout=&quot;@layout/header_menu_drawer&quot;
        app:menu=&quot;@menu/menu_drawer&quot; /&gt;

&lt;/androidx.drawerlayout.widget.DrawerLayout&gt;

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setSupportActionBar(binding.materialToolbar)
        supportActionBar?.title = &quot;Test&quot;
    }
}

HomeFragment.kt

class HomeFragment: Fragment() {
    private lateinit var binding: HomeFragmentBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        activity?.actionBar?.title = &quot;Home 1&quot; /* actionBar == null */
         
        /* supportActionBar == null */
        (activity as AppCompatActivity).supportActionBar?.title = &quot;Home 2&quot;
    }

Result of the code that does not comply with the expected

The idea is to remove the top block of the fragment (Calculators) and use the Toolbar (Test). For this I need to be able to adapt the toolbar for each fragment.
从片段更改MaterialToolbar标题 – Kotlin

  • Possible solution <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

So far I have solved it with a ViewModel observer. I don't know if it's a correct solution, but it works. Any comment is welcome, both to confirm that it is a valid solution and if it is not.

ToolbarVM.kt

    class ToolbarVM(app: Application) : AndroidViewModel(app) {
    
        private val _title = MutableLiveData&lt;String&gt;()
        var title: LiveData&lt;String&gt; = _title
    
        fun setTitle(newTitle: String){
            _title.value = newTitle
        }
    }

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val toolbarVm: ToolbarVM by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        setSupportActionBar(binding.materialToolbar)

        val titleObserver = Observer&lt;String&gt; { newTitle -&gt;
            binding.materialToolbar.title = newTitle
        }

        toolbarVm.title.observe(this, titleObserver)
    }
}

HomeFragment

/*You have to instantiate the ToolbarVm and call the setTitle() method*/
private lateinit var toolbarVm: ToolbarVM
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        toolbarVm = activity?.let { ViewModelProvider(it)[ToolbarVM::class.java] }!!
    }

// Call the method where necessary
toolbarVm.setTitle(&quot;Calculators&quot;)

答案1

得分: 0

MainActivity中,您可以直接使用:

binding.materialToolbar.title = "Test";

而当从片段中调用时,您可以执行以下操作:

activity?.findViewById<Toolbar>(R.id.materialToolbar)?.title = "Test";
英文:

From the MainActivity you can directly use:

binding.materialToolbar.title = &quot;Test&quot;

while when calling from a fragment, you can do the following:

activity?.findViewById&lt;Toolbar&gt;(R.id.materialToolbar)?.title = &quot;Test&quot;

答案2

得分: 0

I have solved it thanks to Razvan's answer. It works if I call it from the onViewCreated() function, but it doesn't work the first time the default fragment is loaded with navGraph. So I have placed it in onResume().

HomeFragment.kt

override fun onResume() {
    super.onResume()
    (activity as AppCompatActivity).supportActionBar?.title = getString(R.string.calculators)
}
英文:

I have solved it thanks to Razvan's answer. It works if I call it from the onViewCreated() function, but it doesn't work the first time the default fragment is loaded with navGraph. So I have placed it in onResume()

HomeFragment.kt

override fun onResume() {
    super.onResume()
    (activity as AppCompatActivity).supportActionBar?.title = getString(R.string.calculators)
}

huangapple
  • 本文由 发表于 2023年2月10日 07:47:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75405616.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定