web-dev-qa-db-fra.com

Comment implémenter un ViewPager à l'aide du nouveau composant d'architecture de navigation?

J'ai une application avec BottomNavigationView et ViewPager. Comment est-il possible de l'implémenter à l'aide du nouveau "composant d'architecture de navigation?"

Quelle est la meilleure pratique?

Merci beaucoup

12
MaksymDovbnia

L'implémentation par défaut de BottomNavigationView avec Navigation Arch Component n'a pas fonctionné pour moi. Lorsque vous cliquez sur les onglets, cela commence par les graphiques de navigation.

J'ai besoin de 5 onglets au bas de l'écran et d'un backstack séparé pour chacun des onglets. Ce qui signifie que lorsque vous passez d'un onglet à l'autre, vous retrouvez toujours exactement le même état qu'avant votre départ (comme sur Instagram).

Mon approche est la suivante:

  1. Mettez ViewPager et BottomNavigationView dans activity_main.xml 
  2. Définissez OnNavigationItemSelectedListener sur BottomNavigationView dans MainActivity.kt
  3. Créez des fragments de conteneur distincts pour chacun des onglets (ils constitueront le point de départ de chaque onglet)
  4. include NavHostFragment à l'intérieur du xml du conteneur.
  5. Implémentez le code nécessaire pour le composant Navigation Arch dans chacun des fragments de conteneur.
  6. Créer un graphique pour chacun des onglets

Remarque: chacun des graphiques peut interagir.

Le point important ici est que nous plaçons Toolbar not en activité mais dans le conteneur. Ensuite, nous appelons setupWithNavController() sur la barre d’outils elle-même sans le définir comme supportActionBar. De cette façon, les titres de la barre d’outils seront automatiquement mis à jour et le bouton Back/Up sera géré automatiquement.

Résultats: 

  • ViewPager stockait les états de chaque onglet.
  • Ne vous inquiétez pas des transactions de fragment.
  • SafeArgs et DeepLinking fonctionnent comme prévu.
  • Nous avons un contrôle total sur BottomNavigationManager et ViewPager (c’est-à-dire que nous pouvons implémenter OnNavigationItemReselectedListener et décider de faire défiler des listes dans l’onglet actuel en haut avant de faire sauter backstack).

Code:

activity_main.xml

<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.viewpager.widget.ViewPager
        Android:id="@+id/main_view_pager"
        Android:layout_width="match_parent"
        Android:layout_height="0dp"
        Android:layout_weight="1" />

    <com.google.Android.material.bottomnavigation.BottomNavigationView
        Android:id="@+id/main_bottom_navigation_view"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:background="?android:attr/windowBackground"
        app:menu="@menu/navigation" />

</LinearLayout>

MainActivity.kt

import kotlinx.Android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private lateinit var viewPagerAdapter: ViewPagerAdapter

    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
        when (item.itemId) {
            R.id.navigation_tab_1 -> {
                main_view_pager.currentItem = 0
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_tab_2 -> {
                main_view_pager.currentItem = 1
                return@OnNavigationItemSelectedListener true
            }
        }
        false
    }

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

        viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
        main_view_pager.adapter = viewPagerAdapter

        main_bottom_navigation_view.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
    }
}

ViewPagerAdapter.kt

class ViewPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> Tab1ContainerFragment()
            else -> Tab2ContainerFragment()
        }
    }

    override fun getCount(): Int {
        return 2
    }
}

fragment_tab_1_container.xml

<RelativeLayout 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=".Tab1ContainerFragment">

    <androidx.appcompat.widget.Toolbar
        Android:id="@+id/tab_1_toolbar"
        Android:layout_width="match_parent"
        Android:layout_height="?attr/actionBarSize"
        Android:background="@color/colorPrimary"
        Android:theme="@style/ThemeOverlay.AppCompat.Dark" />

    <fragment
        Android:id="@+id/tab_1_nav_Host_fragment"
        Android:name="androidx.navigation.fragment.NavHostFragment"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/navigation_graph_tab_1" />

</RelativeLayout>

Tab1ContainerFragment.kt

class Tab1ContainerFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_tab_1_container, container, false)
    }

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

        val toolbar = view.findViewById<Toolbar>(R.id.tab_1_toolbar)

        val navHostFragment = childFragmentManager.findFragmentById(R.id.tab_1_nav_Host_fragment) as NavHostFragment? ?: return

        val navController = navHostFragment.navController

        val appBarConfig = AppBarConfiguration(navController.graph)

        toolbar.setupWithNavController(navController, appBarConfig)
    }
}

Nous pouvons créer autant de graphiques de navigation que vous le souhaitez:

 navigation graphs

Mais nous avons besoin d’un graphique séparé pour chaque onglet:

<navigation 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/navigation_graph_tab_1"
    app:startDestination="@id/tab1StartFragment">

    <fragment
        Android:id="@+id/tab1StartFragment"
        Android:name="com.marat.Android.bottomnavigationtutorial.Tab1StartFragment"
        Android:label="fragment_tab_1_start"
        tools:layout="@layout/fragment_tab_1_start">
        <action
            Android:id="@+id/action_tab_1_to_content"
            app:destination="@id/navigation_graph_content" />
    </fragment>

    <include app:graph="@navigation/navigation_graph_content" />
</navigation>

Ici, commencer fragment de destination est tout fragment que vous souhaitez voir apparaître en tant que premier écran dans l'onglet.

6
Marat

J'ai implémenté Android Arch Navigations avec viewpager. jetez un coup d'oeil s'il vous plait. Toute amélioration est la bienvenue. Permet d'apprendre à se réunir.

https://github.com/Maqsood007/AndroidJetpack/tree/master/ArchNavViewPagerImpl

0
Muhammad Maqsood

Nous pouvons implémenter facilement l’utilisation du composant de navigation inférieure et de NavigationGraph.

Vous devez créer le fragment correspondant pour chaque menu de navigation inférieur 

nav_graph.xml

 <?xml version="1.0" encoding="utf-8"?>
    <navigation 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/nav_graph"
        app:startDestination="@id/actionHome">

        <fragment
            Android:id="@+id/actionHome"
            Android:name="com.sample.demo.fragments.Home"
            Android:label="fragment_home"
            tools:layout="@layout/fragment_home">
            <action
                Android:id="@+id/toExplore"
                app:destination="@id/actionExplore" />
        </fragment>
        <fragment
            Android:id="@+id/actionExplore"
            Android:name="com.sample.demo.fragments.Explore"
            Android:label="fragment_explore"
            tools:layout="@layout/fragment_explore" />
        <fragment
            Android:id="@+id/actionBusiness"
            Android:name="com.sample.demo.fragments.Business"
            Android:label="fragment_business"
            tools:layout="@layout/fragment_business" />
        <fragment
            Android:id="@+id/actionProfile"
            Android:name="com.sample.demo.fragments.Profile"
            Android:label="fragment_profile"
            tools:layout="@layout/fragment_profile" />

    </navigation>

Chaque identifiant de fragment de navigation et identifiant d'élément de menu de navigation inférieur doit être identique. Par exemple ici 

 <fragment
  Android:id="@+id/actionBusiness"
 Android:name="com.sample.demo.fragments.Business"
                Android:label="fragment_business"
                tools:layout="@layout/fragment_business" />

En bas, dans le menu de navigation navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">

    <item
        Android:id="@+id/actionExplore"
        Android:icon="@drawable/ic_search_24dp"
        Android:title="@string/explore" />

    <item
        Android:id="@+id/actionBusiness"
        Android:icon="@drawable/ic_business_24dp"
        Android:title="@string/business" />

    <item
        Android:id="@+id/actionProfile"
        Android:icon="@drawable/ic_profile_24dp"
        Android:title="@string/profile" />


</menu>

Définissez le fichier nav_graph.xml sur le fragment palceholder dans activity_main.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:id="@+id/container"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="@drawable/gradient_bg"
    Android:focusable="true"
    Android:focusableInTouchMode="true"
    tools:context=".MainActivity"
    tools:layout_editor_absoluteY="25dp">

    <Android.support.design.widget.BottomNavigationView
        Android:id="@+id/navigation"
        Android:layout_width="0dp"
        Android:layout_height="wrap_content"
        Android:layout_marginStart="0dp"
        Android:layout_marginEnd="0dp"
        Android:background="@color/semi_grey"
        app:itemIconTint="@drawable/bottom_bar_nav_item"
        app:itemTextColor="@drawable/bottom_bar_nav_item"
        app:labelVisibilityMode="labeled"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/navigation" />

    <include
        Android:id="@+id/appBarLayout"
        layout="@layout/app_bar"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <fragment
        Android:id="@+id/mainNavigationFragment"
        Android:name="androidx.navigation.fragment.NavHostFragment"
        Android:layout_width="0dp"
        Android:layout_height="0dp"
        Android:paddingBottom="@dimen/activity_horizontal_margin"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@+id/navigation"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
        app:navGraph="@navigation/nav_graph" />

</Android.support.constraint.ConstraintLayout>

Mapper le graphique de navigation en fragment ici app: navGraph = "@ navigation/nav_graph"

Après cela, implémentez le graphique de navigation et le composant bottomNavigation dans MainActivity.Java.

 BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        NavController navController = Navigation.findNavController(this, R.id.mainNavigationFragment);
        NavigationUI.setupWithNavController(navigation, navController); 

À votre santé!!!

0
Karthikkumar