我正在应用单活动架构,我想通过工具栏使用顶部固定栏。
在我的项目中,工具栏的形式因片段而异,形式如下:
在MainFragment和一两个Fragment中,工具栏有一个drawerLayout和两个菜单选项,而在除此之外的所有Fragment中,它都有一个后退按钮,没有菜单选项。
但我不知道如何更改每个片段的工具栏布局。
我有两个改变工具栏布局的想法。 第一种方法是使用 Activity xml 的工具栏,并在使用 menuProvider 移动片段时更改代码上的菜单。 像这样:
MainActivity.kt
private fun initToolbar() {
setSupportActionBar(binding.content.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_action_open_drawer)
supportActionBar?.setDisplayShowTitleEnabled(false)
binding.content.toolbar.title = "test"
}
private fun initMenuProvider() {
addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.toolbar_activity, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
when (menuItem.itemId) {
android.R.id.home -> { // for open drawerLayout
binding.drawerLayout.openDrawer(GravityCompat.START)
}
}
return true
}
})
}
fun changeToolbar(menuProvider: MenuProvider, title: String) {
supportActionBar?.setHomeAsUpIndicator(null)
addMenuProvider(menuProvider)
binding.content.toolbar.title = title
}
其他片段.kt
override fun onViewCreated() {
super.onViewCreated(view, savedInstanceState)
val menuProvider = object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.toolbar_nothing, menu) // empty menu layout
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return true
}
}
requireActivity().changeToolbar(menuProvider!!, "Other Fragment")
requireActivity().invalidateOptionsMenu()
}
此代码成功将除雾标记更改为后退按钮,并将工具栏的标题固定为片段标题。 但是,仍然剩下两个菜单选项,即使按下返回按钮, openDrawer() 也会运行。 即使这种方式工作正常,我也必须为每个片段的 onViewCreated 运行 Activity 的changeToolbar()。
另一种方式是不在activity中管理工具栏,而是为每个fragment将工具栏添加到xml中。但我认为这将是一个非常低效的操作。
我该用什么方法?
我用以下方法解决了。
切勿使用
setSupportActionBar()
在我的项目中,存在以下情况:
popBackStack()
).解决方法如下:
将每个工具栏布局添加到MainActivity。 (如果您想创建一个
toolbar_layout.xml
文件并包含布局也没关系)
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/default_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintTop_toTopOf="parent">
</androidx.appcompat.widget.Toolbar>
<androidx.appcompat.widget.Toolbar
android:id="@+id/backstack_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone">
</androidx.appcompat.widget.Toolbar>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true"
android:layout_marginTop="?attr/actionBarSize"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
...
</androidx.constraintlayout.widget.ConstraintLayout>
调整Activity中移动fragment所需的工具栏的可见性。在这个项目中,使用了Jetpack Navigation,因此使用了navController中的
addOnDestinationChangedListener
。
private fun initNavigationEvents() {
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.mainFragment,
R.id.fragmentA,
R.id.fragmentB,
)
)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
navController = navHostFragment.navController
navController.addOnDestinationChangedListener { _, destination, _ ->
when (destination.id) {
R.id.mainFragment, R.id.fragmentA, R.id.fragmentB -> {
mViewDataBinding.defaultToolbar.visibility = View.VISIBLE
mViewDataBinding.backstackToolbar.visibility = View.GONE
}
else -> {
mViewDataBinding.defaultToolbar.visibility = View.GONE
mViewDataBinding.backstackToolbar.visibility = View.VISIBLE
}
}
}
...
}
在Activity中添加DrawerLayout。
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.MainActivity">
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:openDrawer="start">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
// toolbars
// FragmentContainerView
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_marginEnd="-64dp"
android:fitsSystemWindows="true"
app:headerLayout="@layout/navigation_left_drawer_header"
app:menu="@menu/bottom_nav_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
如果toolbar设置为ActionBar,可以通过
MenuProvider
来膨胀菜单,并通过android.R.id.home
中的onMenuItemSelected
指定home的动作。
但是,只有在仅使用一个工具栏时才应使用此方法,并且如果您想对每个片段使用不同的工具栏,则不应将其指定为 ActionBar。因此,菜单必须在工具栏上展开,而不指定 ActionBar。
在工具栏中,Home按钮的图像可以更改为
toolbar.setNavigationIcon()
,并且可以使用toolbar.setNavigationOnClickListener
设置点击事件。
private fun initDefaultToolbar() {
mViewDataBinding.defaultToolbar.inflateMenu(R.menu.toolbar_activity)
mViewDataBinding.defaultToolbar.setNavigationIcon(R.drawable.ic_action_open_drawer)
mViewDataBinding.defaultToolbar.setOnMenuItemClickListener {
when (it.itemId) {
R.id.item1 -> {
Toast.makeText(this@MainActivity, "item1 clicked", Toast.LENGTH_SHORT).show()
return@setOnMenuItemClickListener true
}
R.id.item2 -> {
Toast.makeText(this@MainActivity, "item2 clicked", Toast.LENGTH_SHORT).show()
return@setOnMenuItemClickListener true
}
else -> {
return@setOnMenuItemClickListener false
}
}
}
mViewDataBinding.defaultToolbar.setNavigationOnClickListener {
mViewDataBinding.drawerLayout.openDrawer(GravityCompat.START)
}
}
private fun initBackstackToolbar() {
mViewDataBinding.backstackToolbar.setNavigationIcon(R.drawable.ic_action_back)
mViewDataBinding.backstackToolbar.setNavigationOnClickListener {
navController.popBackStack()
}
}
您可以通过添加 ImageView 来指示徽标和 TextView 来指示工具栏中的标题并根据需要调整可见性来轻松自定义它。
<androidx.appcompat.widget.Toolbar
android:id="@+id/default_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/app_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_launcher_foreground"
android:visibility="@{!vm.titleVisibility}" />
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@{vm.title}"
android:visibility="@{vm.titleVisibility}" />
</androidx.appcompat.widget.Toolbar>
<androidx.appcompat.widget.Toolbar
android:id="@+id/backstack_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone">
<TextView
android:id="@+id/toolbar_title2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@{vm.title}"
android:visibility="@{vm.titleVisibility}" />
</androidx.appcompat.widget.Toolbar>
我通过将片段的标题从片段的 onViewCreated 传递到 Activity 并将数据传递到 ViewModel 并对其进行分支来实现它。