英文:
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
<?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")
答案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 = "Test"
while when calling from a fragment, you can do the following:
activity?.findViewById<Toolbar>(R.id.materialToolbar)?.title = "Test"
答案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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论