66 votes

Comment utiliser TabLayout avec ViewPager2 dans Android ?

Je veux utiliser com.google.android.material.tabs.TabLayout avec le nouveau composant Android ViewPager mise en œuvre androidx.viewpager2.widget.ViewPager2 . Cependant, le setupWithViewPager(..) méthode fournie par TabLayout ne supporte que l'ancien ViewPager mise en œuvre. Existe-t-il un moyen de lier un TabLayout à un ViewPager2 facilement ?

94voto

Nikola Despotoski Points 13670

Vous devez utiliser ce TabLayoutMediator qui imite tabLayout.setupWithViewPager() et met en place le ViewPager2 avec Tablayout . Sinon, vous devrez rédiger votre propre adaptateur qui combinera les deux parties.

Son code ressemblera à ceci en kotlin

TabLayoutMediator(tabLayout, viewPager) { tab, position ->
  tab.text = tabTitles[position]
}.attach()

32voto

Nilesh Rathod Points 34836

UPDATE

Vérifiez ceci Créer des vues glissantes avec des onglets en utilisant ViewPager2

Voici la réponse mise à jour Comment utiliser TabLayout avec ViewPager2 dans Android ?

Maintenant, nous n'avons pas besoin de créer une classe à partir de TabLayoutMediator

Utilisez ci-dessous dependencies

implementation 'com.google.android.material:material:1.1.0-alpha08'
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'

CODE ÉCHANTILLON

Mise en page XMl

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
        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">

    <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

        <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewpager"
            app:layout_anchor="@id/tabs"
            app:layout_anchorGravity="bottom"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
    />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Activité

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import com.google.android.material.tabs.TabLayoutMediator

import com.google.android.material.tabs.TabLayout

class MainActivity : AppCompatActivity() {

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

//        setSupportActionBar(toolbar)
        viewpager.adapter = AppViewPagerAdapter(supportFragmentManager, lifecycle)

        TabLayoutMediator(tabs, viewpager, object : TabLayoutMediator.OnConfigureTabCallback {
            override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
                // Styling each tab here
                tab.text = "Tab $position"
            }
        }).attach()

    }
}

UPDATE

Si vous utilisez implementation 'com.google.android.material:material:1.1.0-alpha10' puis utilisez le code ci-dessous

        TabLayoutMediator(tabs, viewpage,
        TabLayoutMediator.TabConfigurationStrategy { tab, position ->
            when (position) {
                0 -> { tab.text = "TAB ONE"}
                1 -> { tab.text = "TAB TWO"}
            }
        }).attach()

SORTIE

enter image description here

30voto

Pas de bidouillages, pas d'extensions, pas de TabLayoutMediator.

Je suis sur implementation 'com.google.android.material:material:1.2.0-alpha02' et faire ce qui suit sans ayant besoin du TabLayoutMediator. Au lieu de cela, je lie le TabLayout avec le ViewPager2 en utilisant la méthode décrite ci-dessous. ici . J'ai également ajouté un exemple fonctionnel sur github. ici . Je pense avoir réduit la solution à un exemple fonctionnel minimal. Je vais expliquer les points importants.

Ajout des éléments au modèle

Tout d'abord, nous devons ajouter le TabLayout et le ViewPager2 à la disposition. Je les ai placés à l'intérieur d'un LinearLayout et d'un CoordinatorLayout, mais vous pouvez faire ce que vous voulez, bien sûr.

<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
    tools:context=".MainActivity">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
            <androidx.viewpager2.widget.ViewPager2
                android:id="@+id/pager"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </LinearLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Connexion d'un adaptateur au viewpager

L'adaptateur est donc chargé de fournir les bons fragments à l'activité. Vous devrez étendre FragmentStateAdapter ce que j'ai fait très simplement comme ci-dessous (c'est une classe privée car elle est déclarée dans mon MainActivity.java ici) :

    private class ViewStateAdapter extends FragmentStateAdapter {

        public ViewStateAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
            super(fragmentManager, lifecycle);
        }

        @NonNull
        @Override
        public Fragment createFragment(int position) {
            // Hardcoded in this order, you'll want to use lists and make sure the titles match
            if (position == 0) {
                return new BarFragment();
            }
            return new FooFragment();
        }

        @Override
        public int getItemCount() {
            // Hardcoded, use lists
            return 2;
        }
    }

Je peux alors connecter mon propre adaptateur au ViewPager comme ci-dessous :

FragmentManager fm = getSupportFragmentManager();
ViewStateAdapter sa = new ViewStateAdapter(fm, getLifecycle());
final ViewPager2 pa = findViewById(R.id.pager);
pa.setAdapter(sa);

J'ai ajouté les fragments à mon viewpager. (Parce que j'ai codé en dur les fragments dans mon adaptateur, vous devriez utiliser une liste et quelque chose comme une méthode 'addFragment' ou quelque chose comme ça)

Le TabLayout

Ensuite, avec

TabLayout tabLayout = findViewById(R.id.tabLayout);
tabLayout.addTab(tabLayout.newTab().setText("Bar"));
tabLayout.addTab(tabLayout.newTab().setText("Foo"));

J'ajoute deux onglets à mon TabLayout, affichant les titres mais ne me permettant pas encore de passer aux fragments.

Connexion de TabLayout à l'adaptateur

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                pa.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

Cela devrait être assez simple. L'utilisateur clique sur un onglet, je récupère la position dans mon callback et je fixe simplement l'élément actuel de l'adaptateur à cette position.

Changement d'onglet lors du glissement de la souris

Enfin, nous couplons lorsque l'utilisateur passe le fragment pour définir l'élément correct de l'onglet comme sélectionné

pa.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
    @Override
    public void onPageSelected(int position) {
        tabLayout.selectTab(tabLayout.getTabAt(position));
    }
});

19voto

Santanu Sur Points 5061

Initialiser le TabLayoutMediator avec un objet de TabLayout , ViewPager2 , autoRefresh -- de type booléen, et un objet de type OnConfigurationChangeCallback .

TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager2, true, new TabLayoutMediator.OnConfigureTabCallback() {
  @Override
  public void onConfigureTab(TabLayout.Tab tab, int position) {
    // position of the current tab and that tab  
  }
});

Enfin, il suffit d'appeler attach() à la TabLayoutMediator objet pour relier le tablayout au viewpager :-

 tabLayoutMediator.attach();

autoRefresh - si elle est réglée sur true -- ( Par défaut, elle est mise à true )

RECREATES tous les onglets de la tabLayout si notifyDataSetChanged est appelé au viewpager adapter .

Utilisez le contenu de TabLayoutMediator.java

8voto

seyfx Points 26

Vous pouvez utiliser la fonction d'extension Kotlin :

fun TabLayout.setupWithViewPager(viewPager: ViewPager2, labels: List<String>) {

    if (labels.size != viewPager.adapter?.itemCount)
        throw Exception("The size of list and the tab count should be equal!")

    TabLayoutMediator(this, viewPager,
        TabLayoutMediator.TabConfigurationStrategy { tab, position ->
            tab.text = labels[position]
        }).attach()
}

Et l'appeler :

 tabLayout.setupWithViewPager(viewPager, listOf("Tab A", "Tab B"))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X