Migrer son ActionBar vers la ToolBar (Quatrième Partie) : Mise en place des onglets et du ViewPager

b2ap3_thumbnail_Android2ee-logo-BIG_blue-1024x375.png

Et bonjour tout le monde,

Pour finir cette série sur la ToolBar, il ne nous reste plus qu'à mettre en place la ToolBar avec une ligne d'onglets et/ou avec un ViewPager.

Commençons par la ligne d'onglets.

ToolBar et TabLayout

Nous voulons simplement avoir une activité avec des onglets et la ToolBar :

ToolBar et TabLayout CenterFixed        ToolBar et TabLayout CenterFixed nTabs
ToolBar et tablayout FillScrolable        ToolBar et TabLayout CenterScrollable nTabs

Pour ajouter cette ligne d'onglets, rien de plus facile, il faut tout d'abord définir en xml sa ligne d'onglets et les construire coté Java. Aucune surprise ne vous attend. Nous utilisons uniquement les composants de la DesignLibrary pour la mise en place des onglets et tout se déroule alors facilement.

Il y a deux paramètres que nous pouvons modifier pour le comportement de la ToolBar: La notion de Gravité et la notion de Mode.

La gravité possède deux valeurs Center ou Fill. Center rassemble les onglets au centre de l'écran en mode wrapContent alors que Fill répartit uniformément l'espace disponible pour chaque onglet.

Le mode permet simplement de dire si vous souhaitez que vos onglets soient scrollables ou pas. S'ils ne sont pas scrollables, ils s'affichent tous dans l'espace disponible, ce qui veut dire qu'ils sont compressés et peuvent ne pas avoir la place de s'afficher complètement.

Mise en place

Le fichier de Layout

Commençons par examiner le fichier de layout:

res\layout\activity_activity_with_tabs_nav.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ActivityWithTabsNav">
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"/>
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF00FF"
android:fillViewport="true" />
<TextView
android:id="@+id/txvState"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/btnChangeMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btnChangeTabMode"/>
<Button
android:id="@+id/btnChangeGravity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btnChangeGravity"/>
<Button
android:id="@+id/btnAddTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btnAddTab"/>
LinearLayout>

Il n'y a pas grand-chose à dire, si ce n'est que TabLayout appartient à la DesignLibrary et la ToolBar à la support.v7.

Le code Java

Le code Java de l'activité est assez simple. Il y a trois étapes auxquelles il faut faire attention :

  • Instancier la ToolBar et le TabLayout

  • Construire les onglets du TabLayout

  • Ajouter un listener au TabLayout pour être avertit des changements d'onglets.

Tout se fait dans le onCreate de votre activité (ou dans le onCreateView de votre fragment).

Ainsi, comme d'habitude, dans la méthode onCreate, on instancie la ToolBar:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set your view
setContentView(R.layout.activity_activity_with_tabs_nav);
//find the Toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//use it as your action bar
setSupportActionBar(toolbar);
//Add subtitle
getSupportActionBar().setSubtitle("Using ToolBar");
//Find the Tab Layout
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
//Define its gravity and its mode
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
//Define the color to use (depending on the state a different color should be disaplyed)
//Works only if done before adding tabs
tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color));
//populate your TabLayout
tabLayout.addTab(tabLayout.newTab().setText("Tab 1").setIcon(R.drawable.ic_tab));
tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));
//add a listener
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {/*do your navigation*/}
@Override
public void onTabUnselected(TabLayout.Tab tab) {/*do nothing*/}
@Override
public void onTabReselected(TabLayout.Tab tab) {/*do nothing*/}
});
...
}

Comme d'habitude, on récupère la ToolBar et on l'affecte à l'activité comme étant son ActionBar.

Puis on s'occupe du TabLayout. Ici, il n'y a plus besoin d'appeler la méthode setup sur le TabLayout, l'initialisation est automatique. Il vous suffit de le récupérer (findViewById), de lui affecter son Mode et sa Gravité puis de lui ajouter ses onglets via la méthode addTab en fournissant pour chaque onglet, un texte et un icone optionnel.

Enfin, il ne vous reste plus qu'à ajouter le TabListener pour interagir avec l'utilisateur et changer le fragment affiché dans l'onglet. Vous pouvez aussi mettre des vues en utilisant la méthode addView(View view, int index, LayoutParameter layoutParam).

Mais attention, la philosophie à changer, il n'y a plus besoin que votre TabLayout contienne les vues pour chaque onglet. Il n'est qu'un conteneur d'onglets; uniquement la ligne qui affiche les boutons, à vous de gérer la mise à jour de la vue / du fragment sous cette ligne. Je pense que c'est la bonne manière d'aborder ce composant avec les fragments en utilisant ces derniers de manière dynamique.

Et voilà, c'est tout, en fait, ce n'était pas compliqué.

 Ah oui, j'oubliais, les imports utilisés pour cette activité sont:

importandroid.support.design.widget.TabLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

Gestion des couleurs des onglets

Une dernière précision sur l'affectation des couleurs à vos boutons d'onglets. Pour effectuer cela, on s'appuie sur un fichier de couleurs un peu particulier, un SelectorColor (identique à un SelectorDrawable dans l'idée). Un SelectorColor est une couleur qui en fonction de l'état du composant (enabled/selected/hover...) possède une valeur spécifique:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="@color/testcolor2" />
<item android:state_selected="true" android:color="@color/testcolor3" />
<item android:color="@color/testcolor5"/>
selector>

Il ne reste plus qu'à affecter cette couleur à nos onglets et automatiquement (s'ils sont sélectionnés ou pas) s'afficheront de manière différente (avec une couleur différente).

tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color));

Vous devez affecter les couleurs à vos onglets AVANT d'ajouter des boutons à votre ligne d'onglet (bref avant d'appeler la méthode addTab).

 

ToolBar et ViewPager

Ces composants sont faits pour marcher ensemble simplement. Il suffit de déclarer la TabLayout, le ViewPager et la ToolBar dans votre fichier de layout, puis côté Java, d'ajouter la TabLayout comme précedement et de lier le ViewPager au TabLayout.

ToolBar et ViewPager        ToolBar et ViewPager scrolling

 

Mise en place

Le fichier de Layout

Commençons par examiner le fichier de layout:

res\layout\activity_tabs_view_pager.xml

!--xml version="1.0" encoding="utf-8"--> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.android2ee.formation.lollipop.toolbar.tabsnav.ActivityTabsNavViewPager">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"/>
!--For more information: <android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF00FF"
android:fillViewport="true" />
<android.support.v4.view.ViewPager
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/viewpager"
android:background="#FF00F0F0"
android:fillViewport="true">
android.support.v4.view.ViewPager>
LinearLayout>
 

Il n'y a pas grand-chose à dire, si ce n'est que TabLayout appartient à la DesignLibrary et la ToolBar à la support.v7 et le ViewPager à la support v4 (inclus dans la support v7).

Le code Java

Le code Java de l'activité est assez simple. Il y a quatre étapes auxquelles il faut faire attention :

  • Instancier la ToolBar, le ViewPager et le TabLayout,
  • Construire les onglets du TabLayout,
  • Ajouter un listener au TabLayout pour être avertit des changements d'onglets (ce n'est ici pas obligatoire, je le conseille pour la restauration de l'onglet courant quand l'utilisateur revient dans votre activité),
  • Lier le ViewPager au TabLayout.

 Tout se fait dans le onCreate de votre activité (ou dans le onCreateView de votre fragment).

Ainsi, comme d'habitude, dans la méthode onCreate, on instancie la ToolBar:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs_nav_view_pager);
//find the Toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//use it as your action bar
setSupportActionBar(toolbar);
//Add subtitle
getSupportActionBar().setSubtitle("Using ToolBar");
//Find the Tab Layout
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
//Define its gravity and its mode
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
//instanciate the PageAdapter
pagerAdapter=new MyPagerAdapter(this);
//Define the color to use (depending on the state a different color should be disaplyed)
//Works only if done before adding tabs
tabLayout.setTabTextColors(getResources().getColorStateList(R.color.tab_selector_color));
//Find the viewPager
viewPager = (ViewPager) super.findViewById(R.id.viewpager);
// Affectation de l'adapter au ViewPager
viewPager.setAdapter(pagerAdapter);
viewPager.setClipToPadding(false);
viewPager.setPageMargin(12);
//Add animation when the page are swiped
//this instanciation only works with honeyComb and more
//if you want it all version use AnimatorProxy of the nineoldAndroid lib
//@see:http://stackoverflow.com/questions/15767729/backwards-compatible-pagetransformer
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
viewPager.setPageTransformer(true, new MyPageTransformer(this));
}
//AND CLUE TABLAYOUT AND VIEWPAGER
tabLayout.setupWithViewPager(viewPager);
}

Comme d'habitude, on récupère la ToolBar et on l'affecte à l'activité comme étant son ActionBar.

Puis on s'occupe du TabLayout (paragraphe précédent).

Enfin, il ne vous reste plus qu'à ajouter le TabListener pour se souvenir de l'onglet dans le quel est l'utilisateur. Ainsi, quand l'utilisateur revient dans votre activité, si elle est encore dans la liste des applications récentes (dans votre LRUCach pour être exact), vous pouvez alors le replacer dans l'onglet qu'il vient de quitter.

 

Enfin, pour rappel, le code du ViewPager est le suivant:

public class MyPagerAdapter extends FragmentPagerAdapter {
/**
* The list of ordered fragments
*/
private final ArrayList fragments; //On fournit à l'adapter la liste des fragments à afficher

/***
* The constructor
* @param ctx The Context
*/
public MyPagerAdapter(ActivityTabsNavViewPager ctx) {
super(ctx.getSupportFragmentManager());
fragments = new ArrayList();
//A stuff I never did before, instanciate my fragment
Fragment frag = new MyFragment1();
fragments.add(frag);
frag = new MyFragment2();
fragments.add(frag);
frag = new MyFragment3();
fragments.add(frag);
frag = new MyFragment4();
fragments.add(frag);
frag = new MyFragment5();
fragments.add(frag);
}

/**
* This method may be called by the ViewPager to obtain a title string
* to describe the specified page. This method may return null
* indicating no title for this page. The default implementation returns
* null.
*
* @param position The position of the title requested
* @return A title for the requested page
*/
@Override
public CharSequence getPageTitle(int position) {
return "This is the Page "+position;
}

@Override
public Fragment getItem(int position) {
return fragments.get(position);
}

@Override
public int getCount() {
return 5;
} }

 Ah oui, j'oubliais, les imports utilisés pour cette activité sont:

importandroid.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

 

 Conclusion

Je finis ces blogs, concernant la ToolBar, comme toujours, en remerciant Chris Banes (@chrisbanes) car  c'est à lui que l'on doit cette simplification et surtout cette libération de l'ActionBar,

so Thanks a billion Mr Banes.

Le tutorial ?

Bien sûr, il est fourni, il est sur GitHub, ici : https://github.com/MathiasSeguy-Android2EE/ToolBar4Github (et si vous souhaitez lui ajouter des étoiles à ce projet, je suis à fond, cela me fera plaisir, je l'avoue).

 

Les prochaines formations Android d’Android2EE 
Lille: Du 15 au 19 février 2015 , Formation complète.

Paris: Du 14 au 18 mars 2015 , Formation complète.

 

A bientôt.

Mathias Séguy
[email protected]

Fondateur Android2EE
Formation – Expertise – Consulting Android.
Ebooks pour apprendre la programmation sous Android.
AndroidEvolution

Suivez moi sur Twitter
Rejoignez mon réseau LinkedIn 

Pour finir cette série sur la ToolBar, il ne nous reste plus qu'à mettre en place la ToolBar avec une ligne d'onglets et/ou avec un ViewPager.

Commençons par la ligne d'onglets.

Related Posts