如何为每个片段应用不同的工具栏(操作栏)布局?

问题描述 投票:0回答:1

我正在应用单活动架构,我想通过工具栏使用顶部固定栏。

在我的项目中,工具栏的形式因片段而异,形式如下:

Main(Home)

a few(1 or 2) fragment with drawer

other fragment

在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中。但我认为这将是一个非常低效的操作。

我该用什么方法?

android kotlin android-fragments android-activity android-toolbar
1个回答
0
投票

我用以下方法解决了。

切勿使用

setSupportActionBar()

在我的项目中,存在以下情况:

  1. 工具栏布局应在总共三个片段中共享:主片段、片段 A 和 B。后退按钮应显示在其余片段中。
  2. 在Main Fragment中,home按钮必须打开导航视图(抽屉),而在带有后退按钮的Fragment中,必须先移动到Fragment再移动。 (
    popBackStack()
    ).
  3. 在主片段中,标题应该是应用程序的徽标,在片段A和B中,标题应该是片段的名称。

解决方法如下:

  1. 将每个工具栏布局添加到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
                }
            }
        }
        ...
    }

  1. 这就是导致activity被分成两部分的部分,正如我在答案顶部所写的,如果不将其用作actionBar,则可以非常简单地解决。

在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()
    }
}

  1. 您可以通过添加 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 并对其进行分支来实现它。

© www.soinside.com 2019 - 2024. All rights reserved.