how to setup different toolbar using navigation controller component?

孤人 提交于 2020-08-01 16:45:59

问题


I am actually not sure, how the correct way or the best practice to set different toolbar using navigation controller component

in my app. I want to set 2 different toolbars.

  1. green toolbar
  2. red toolbar

two toolbars with different colour. this is just to simplify the case, actually I have multiple toolbars

I am using navigation controller component. and currently on my Main Activity as the host, I set the green toolbar in my main activity using this code

        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)

so what is the best way to set different toolbar using navigation controller component ?

do I have to make those 2 different toolbars in my main activity? or do I have to set fragmentY destination(that has red toolbar) as another activity not as the fragment ?

or.... I don't know....please help :)


回答1:


I add a better answer for this. so according the documentation from here , I need to set the toolbar in each fragment.

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.

so we will add the toolbar in each fragment instead of set it in MainActivity. if you set toolbar in each fragment, it also will make it possible to implement Collapsing Toolbar.

I assume you also use Bottom Navigation View. say for example in your bottom navigation menu you have home, profile and search fragments as top level fragment (root).

so in EACH top level fragment set the toolbar using this code in onViewCreated of your fragment.

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)

you have to pass appBarConfiguration to remove back button in your toolbar. so you have to pass appBarConfiguration in each top level fragment (home,search,profile), not only in your home.

and for the rest of the fragments you don't need to pass appBarConfiguration, so for the rest of your fragments just pass this code in onViewCreated .

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

and if your toolbar has menu, then add this code:

setHasOptionsMenu(true)

(activity as AppCompatActivity).setSupportActionBar(toolbar)

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

to use AppBarConfiguration class , in gradle app you need to use navigation-ui-ktx artifact and you need to add compile options and kotlin options like this

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"
}

don't forget to add noActionBar in your res value style 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>



回答2:


I finally find the solution for this. I don't know if this is the correct way or not, but so far it looks perfect in my project.

1. first step, you have to create xml for your toolbar only, for example :

toolbar_red.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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">

    <android.support.v7.widget.Toolbar
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="#F44336"
            android:theme="?attr/actionBarTheme"
            android:minHeight="?attr/actionBarSize"
            android:id="@+id/toolbarRed"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

</android.support.constraint.ConstraintLayout>

and toolbar_blue.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="wrap_content">

    <android.support.v7.widget.Toolbar
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="#2196F3"
            android:theme="?attr/actionBarTheme"
            android:minHeight="?attr/actionBarSize"
            android:id="@+id/toolbarBlue"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>
</android.support.constraint.ConstraintLayout>

2. and then include that toolbar in your navigation host (main activity) , the activity_main.xml will be like this. the red toolbar visibility by default is visible, and the blue visibility is gone.

<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">


    <include
            android:id="@+id/include_toolbarRed"
            layout="@layout/toolbar_red"
            android:visibility="visible"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" android:layout_width="0dp"
            android:layout_height="wrap_content"/>

    <include
            android:id="@+id/include_toolbarBlue"
            layout="@layout/toolbar_blue"
            android:visibility="gone"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" android:layout_width="0dp"
            android:layout_height="wrap_content"/>


   (other elements here)


</android.support.constraint.ConstraintLayout>

3. set the visibility of that include toolbar when NavController OnDestinationChangedListener is triggered

so basically you will change the toolbar in your navigation host (main activity) not in your destination (fragment)

whenever the destination changed, then set the include toolbar visibility. my MainActivity.kt file will be like this

class MainActivity : AppCompatActivity(), NavController.OnDestinationChangedListener {

    lateinit var navController : NavController
    lateinit var redToolbar: Toolbar
    lateinit var blueToolbar: Toolbar

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

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

        redToolbar = findViewById<ConstraintLayout>(R.id.include_toolbarRed).findViewById(R.id.toolbarRed)
        blueToolbar = findViewById<ConstraintLayout>(R.id.include_toolbarBlue).findViewById(R.id.toolbarBlue)


        setupActionBar()
        setupBottomNavMenu()


        // Add Listeners
        navController.addOnDestinationChangedListener(this)


    }

    private fun setupBottomNavMenu() {
        bottom_nav.setupWithNavController(navController)
    }


    private fun setupActionBar() {

        // set destination_home and destination_camera as the top hierarcy destination (destination for tab bar in bottom navigation view)
        val appBarConfiguration = AppBarConfiguration(setOf(R.id.destination_home, R.id.destination_camera))

        if (include_toolbarRed.visibility == View.VISIBLE) {
            setSupportActionBar(redToolbar)
            redToolbar.setupWithNavController(navController,appBarConfiguration)

        } else if (include_toolbarBlue.visibility == View.VISIBLE) {
            setSupportActionBar(blueToolbar)
            blueToolbar.setupWithNavController(navController,appBarConfiguration)
        }



    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
    }



    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_toolbar, menu)
        return true
    }

    override fun onDestinationChanged(controller: NavController, destination: NavDestination, arguments: Bundle?) {


        if (destination.id == R.id.destination_camera) {
            include_toolbarRed.visibility = View.GONE
            include_toolbarBlue.visibility = View.VISIBLE

        } else {

            include_toolbarRed.visibility = View.VISIBLE
            include_toolbarBlue.visibility = View.GONE
        }

        setupActionBar()


    }
}



回答3:


It whould be more convenient to leave MainActivity layout with just navigation fragment and define needed toolbars in fragments layouts. Then in each fragment onCreateView:

(activity as AppCompatActivity).setSupportActionBar(toolbar)

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

For better example see how this is done in Android-Sunflower app by google: https://github.com/googlesamples/android-sunflower




回答4:


You must set separate toolbar on each fragments, but it a little bit confusing. I used library for solving this problem.

Use the navigation component in the same way. For every fragments do this.

Create toolbar in layout

<?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>

And use 'setupToolbar' method in fragment

class FirstFragment : Fragment(R.layout.fragment_first) {

    ...

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

    ...

}

and don't forget to implement lib on your dependencies, but be careful this lib isn't on release version, and may be changed.

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

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

details: https://github.com/AlexanderGuru/MultipleToolbars



来源:https://stackoverflow.com/questions/57014922/how-to-setup-different-toolbar-using-navigation-controller-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!