如何使用导航控制器组件设置不同的工具栏?

how to setup different toolbar using navigation controller component?

我实际上不确定,使用导航控制器组件设置不同工具栏的正确方法或最佳做法是什么

在我的应用程序中。我想设置 2 个不同的工具栏。

  1. 绿色工具栏
  2. 红色工具栏

两个不同颜色的工具栏。这只是为了简化案例,实际上我有多个工具栏

我正在使用导航控制器组件。目前在我的 Main Activity 作为主机,我使用此代码

在我的 Main activity 中设置了绿色工具栏
        setSupportActionBar(green_toolbar)
        supportActionBar?.setDisplayShowTitleEnabled(false)

        // set up top hierarchy destination
        val appBarConfiguration = AppBarConfiguration(setOf(
            R.id.destination_home,
            R.id.destination_search,
            R.id.destination_user_control,
            R.id.destination_create_event)
        )

        green_toolbar.setupWithNavController(navController,appBarConfiguration)

那么使用导航控制器组件设置不同工具栏的最佳方法是什么?

我是否必须在主 activity 中制作这 2 个不同的工具栏?或者我是否必须将 fragmentY 目标(具有红色工具栏)设置为另一个 activity 而不是片段?

或者....我不知道....请帮忙:)

将 MainActivity 布局保留为仅导航片段并在片段布局中定义所需的工具栏会更方便。 然后在每个片段中 onCreateView:

(activity as AppCompatActivity).setSupportActionBar(toolbar)

toolbar.setNavigationOnClickListener { view ->
    view.findNavController().navigateUp()
}

为了更好的示例,请参阅 google 在 Android-Sunflower 应用程序中如何完成此操作: https://github.com/googlesamples/android-sunflower

下面的答案适用于使用底部导航视图的应用程序,如果您使用的是导航抽屉,则使用

所以根据 here 的文档,我需要在每个片段中设置工具栏。

If, however, your top app bar changes substantially across destinations, then consider removing the top app bar from your activity and defining it in each destination fragment, instead.

所以我们会在每个fragment中添加toolbar,而不是在MainActivity中设置。如果在每个fragment中设置toolbar,也可以实现Collapsing Toolbar。

例如,在您的底部导航菜单中,您将主页、个人资料和搜索片段作为顶级片段(根),如下所示

因此在 EACH 顶级片段中使用此代码在片段的 onViewCreated 中设置工具栏。

val toolbar = view.findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbarInYourFragment)
val appBarConfiguration = AppBarConfiguration(setOf(
    R.id.destination_home,
    R.id.destination_profile  // set all your top level destinations in here
    R.id.destination_search)
)

val navHostFragment = NavHostFragment.findNavController(this);
NavigationUI.setupWithNavController(toolbar, navHostFragment,appBarConfiguration)

您必须通过 appBarConfiguration 才能删除工具栏中的后退按钮。所以你必须在每个顶级片段(主页、搜索、个人资料)中传递 appBarConfiguration,而不仅仅是在你的主页中。

对于其余的片段,您不需要传递 appBarConfiguration,因此对于您的其余片段,只需在 onViewCreated 中传递此代码即可。

val toolbar = view.findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbarInYourFragment)
val navHostFragment = NavHostFragment.findNavController(this);
NavigationUI.setupWithNavController(toolbar, navHostFragment)

如果您的工具栏有菜单,则添加此代码:

setHasOptionsMenu(true)

(activity as AppCompatActivity).setSupportActionBar(toolbar)

toolbar.setNavigationOnClickListener { view ->
    view.findNavController().navigateUp()
}

要使用 AppBarConfiguration class ,在 gradle 应用程序中你需要使用 navigation-ui-ktx 工件并且你需要像这样添加编译选项和 kotlin 选项

android {
   

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }

}


dependencies {

    def nav_version = "2.3.0-alpha04"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

不要忘记在你的 res 值样式中添加 noActionBar xml

 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">


        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>


    </style>


  

您必须在每个片段上设置单独的工具栏,但这有点混乱。我使用库来解决这个问题。

以同样的方式使用导航组件。对于每个片段都这样做。

在布局中创建工具栏

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="20dp"
            android:background="?colorPrimary"
            android:text="Next fragment"
            android:textColor="?android:textColorSecondary" />

    </FrameLayout>

</LinearLayout>

并在片段

中使用'setupToolbar'方法
class FirstFragment : Fragment(R.layout.fragment_first) {

    ...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setupToolbar(toolbar)
    }  

    ...

}

并且不要忘记在你的依赖项上实现 lib,但是要小心这个 lib 没有打开 发布版本,可能会更改。

repositories {
    ...
    maven { url 'https://jitpack.io' }
}

dependencies {
    implementation 'com.github.AlexanderGuru:MultipleToolbars:0.0.1-SNAPSHOT'
}

详情:https://github.com/AlexanderGuru/MultipleToolbars

如果您的应用使用导航抽屉,请使用下面的代码;如果您使用底部导航视图,则使用

首先,您必须从 MainActivity 中删除工具栏,并且必须在每个片段中设置工具栏 xml。如果你在每个片段中设置工具栏,它也可以实现折叠工具栏。根据 here 中的文档,据说

If, however, your top app bar changes substantially across destinations, then consider removing the top app bar from your activity and defining it in each destination fragment, instead.

从 MainActivity 中删除工具栏。像这样设置您的 MainActivity 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:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start"
    tools:context=".MainActivity">

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


        <fragment
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:defaultNavHost="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:navGraph="@navigation/main_graph" />


    </androidx.constraintlayout.widget.ConstraintLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/nav_drawer_header"
        app:menu="@menu/nav_drawer_menu" />

</androidx.drawerlayout.widget.DrawerLayout>

比如我的app会是这样

它有 3 个顶级目的地:消息、聊天和分享

然后像这样设置您的 MainActivity

class MainActivity : AppCompatActivity() {

    lateinit var navController : NavController
    lateinit var appBarConfiguration: AppBarConfiguration


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        appBarConfiguration = AppBarConfiguration(setOf(
            R.id.destination_share,
            R.id.destination_message, // set all your top level destinations in here
            R.id.destination_chat), // don't forget the parentheses
            drawer_layout // include your drawer_layout
        )


        navController = Navigation.findNavController(this,R.id.nav_host_fragment)

    }


    override fun onSupportNavigateUp(): Boolean {
        return NavigationUI.navigateUp(navController,appBarConfiguration)
    }

    
}

EACH顶级片段中,使用下面的代码设置它

class ChatFragment : Fragment() { // for Message and Share Fragment, will be the same

    lateinit var mActivity : FragmentActivity

    override fun onAttach(context: Context) {
        super.onAttach(context)

        activity?.let { mActivity = it }

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_chat, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setUpToolbar()
        
    }

    private fun setUpToolbar() {

        val mainActivity = mActivity as MainActivity
        val navigationView: NavigationView = mActivity.findViewById(R.id.navigation_view)

        mainActivity.setSupportActionBar(toolbar)
        val navController = NavHostFragment.findNavController(this)
        val appBarConfiguration = mainActivity.appBarConfiguration
        NavigationUI.setupActionBarWithNavController(mainActivity,navController,appBarConfiguration)
        NavigationUI.setupWithNavController(navigationView,navController)

    }


}

在子片段中,即如果你想在你的片段中显示后退按钮而不是汉堡包按钮,那么使用与上面相同的代码,除了 setToolbar 方法会有所不同,像这样

private fun setUpToolbar() {

        val mainActivity = mActivity as MainActivity
        val navigationView: NavigationView = mActivity.findViewById(R.id.navigation_view)

        mainActivity.setSupportActionBar(toolbar)
        val navController = NavHostFragment.findNavController(this)
        NavigationUI.setupActionBarWithNavController(mainActivity,navController)
        NavigationUI.setupWithNavController(navigationView,navController)

    }

如果您的工具栏有菜单,则在 setToolbar 方法中添加此代码:

setHasOptionsMenu(true)

toolbar.setNavigationOnClickListener { view ->
    view.findNavController().navigateUp()
}

要使用 AppBarConfiguration class ,在 gradle 应用程序中你需要使用 navigation-ui-ktx 工件并且你需要像这样添加编译选项和 kotlin 选项

android {
   

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }

}


dependencies {

    def nav_version = "2.3.0-alpha04"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

不要忘记在你的 res 值样式中添加 noActionBar xml

 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">


        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>


    </style>