• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Ce cours est en vidéo.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Développez votre premier ViewPager

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction

Dans cette partie, nous allons appliquer ensemble les compétences précédemment acquises sur les fragments. Maintenant que vous êtes devenus incollables à leur sujet, nous allons voir comment les implémenter à travers quelques patterns de navigations vus dans la première partie.

Pour cela, nous allons commencer à parler du ViewPager.

Présentation du ViewPager

Le ViewPager est un pattern introduit par Android dès la version 1.6 (API 4) via le package Android Support, afin d'assurer une navigation horizontale en permettant à l'utilisateur de faire défiler (swipe) les différentes portions du contenu d'une application sur un seul et même écran.

Au sein d'un ViewPager, nous aurons différents fragments matérialisés par des pages.

                               

Implémentation d'un ViewPager

Passons aux choses sérieuses ! Nous allons implémenter ensemble notre premier ViewPager :).

                                                            

Présentation du Pattern Adapter

Mais avant cela, je me dois de vous parler d'un pattern très important sur Android, à savoir le Pattern Adapter.

Vous retrouverez ce concept beaucoup de fois sur Android, notamment lors de la manipulation de RecyclerView ou ListView que nous verrons dans un prochain cours. 

Pour résumer, le Pattern Adapter a pour objectif de faire fonctionner ensemble et correctement deux classes radicalement opposées et incompatibles. On peut illustrer ce concept en prenant l'exemple d'un lecteur de carte SD (agissant comme le ferait un adapter) entre le PC et la carte SD.

En français, vous pouvez également l'appeler "adaptateur".

Création de notre ViewPager

Comme d'habitude, nous allons partir d'une application vierge nouvellement créée. Pour cela, vous pouvez utiliser l'assistant d'Android Studio ou télécharger directement le résultat sur ce lien.

Une fois le projet ouvert, nous allons vérifier que la librairie Android Support est bien installée (car le ViewPager est déclaré à l'intérieur) :

dependencies {
    compile 'com.android.support:appcompat-v7:26.1.0'
}

Nous allons ensuite implémenter notre ViewPager dans le layout (activity_main.xml) de notre activité principale MainActivity :

Fichier activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main_viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Explications : Rien de bien compliqué ici, puisque nous déclarons notre vue ViewPager dans le layout de MainActivity. Cette vue servira de conteneur pour nos différentes pages, représentées par un fragment.

Passons maintenant à la création de notre fragment, qui représentera chacune des pages de notre ViewPager, et que nous appellerons PageFragment. Comme évoqué dans la partie 2, n'hésitez pas à créer le fragment directement depuis l'assistant d'Android Studio pour plus de simplicité... ;)

Ainsi, après cette création assistée, vous devez obtenir deux fichiers, PageFragment.java et fragment_page.xml.

Modifions ensemble le layout de notre fragment PageFragment afin d'y afficher en son centre un TextView :

Fichier fragment_page.xml :

<LinearLayout
    android:id="@+id/fragment_page_rootview"
    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"
    tools:context="com.openclassrooms.myamazingviewpager.Controllers.Fragments.PageFragment"
    android:gravity="center">

    <TextView
        android:id="@+id/fragment_page_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dip"
        android:textSize="25sp"
        android:textStyle="bold"
        android:textColor="#fff"/>

</LinearLayout>

Nous allons ensuite modifier la classe de notre fragment PageFragment, afin que ce dernier puisse mettre à jour son layout à chaque nouveau défilement d'une page.

Fichier PageFragment.java :

public class PageFragment extends Fragment {

    // 1 - Create keys for our Bundle
    private static final String KEY_POSITION="position";
    private static final String KEY_COLOR="color";


    public PageFragment() { }


    // 2 - Method that will create a new instance of PageFragment, and add data to its bundle.
    public static PageFragment newInstance(int position, int color) {

        // 2.1 Create new fragment
        PageFragment frag = new PageFragment();
        
        // 2.2 Create bundle and add it some data
        Bundle args = new Bundle();
        args.putInt(KEY_POSITION, position);
        args.putInt(KEY_COLOR, color);
        frag.setArguments(args);

        return(frag);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        // 3 - Get layout of PageFragment
        View result = inflater.inflate(R.layout.fragment_page, container, false);
        
        // 4 - Get widgets from layout and serialise it
        LinearLayout rootView= (LinearLayout) result.findViewById(R.id.fragment_page_rootview);
        TextView textView= (TextView) result.findViewById(R.id.fragment_page_title);

        // 5 - Get data from Bundle (created in method newInstance)
        int position = getArguments().getInt(KEY_POSITION, -1);
        int color = getArguments().getInt(KEY_COLOR, -1);

        // 6 - Update widgets with it
        rootView.setBackgroundColor(color);
        textView.setText("Page numéro "+position);
        
        Log.e(getClass().getSimpleName(), "onCreateView called for fragment number "+position);

        return result;
    }

}

Explications : Comme nous l'avons évoqué plus haut, ce fragment va être créé puis affiché pour chaque page de notre ViewPager. Cependant, sa couleur de fond et son texte central doivent changer afin de différencier visuellement chaque page :

  • Ligne 1 : Nous déclarons ici des variables statiques servant d'identifiants des futures valeurs passées à notre Bundle.

  • Ligne 2 : Cette méthode, très conventionnelle dans le monde des fragments lors de leur création, va être appelée afin de retourner un fragment (2.1), avec certaines valeurs prédéfinies (2.2) dans son Bundle (ici sa position et sa couleur), dans le but de pouvoir les récupérer lors de son affichage.

  • Ligne 3 : Nous récupérons comme d'habitude, le layout de notre fragment depuis la méthode onCreateView( ).

  • Ligne 4 : Nous récupérons également les vues que nous souhaitons mettre à jour (LinearLayout et TextView).

  • Ligne 5 : Nous avons précédemment (2.2) ajouté des données dans notre Bundle. Il est temps de les récupérer, et c'est ce que nous faisons ici.

  • Ligne 6 : Grâce à ces données récupérées, nous allons pouvoir mettre à jour nos vues (LinearLayout et TextView).

Super ! Notre fragment est défini ainsi que notre ViewPager.

Mais du coup comment les relier ensemble ? :euh:

Grâce à un adapter bien sûr ! Rappelons que ce dernier sert à faire le lien entre notre ViewPager et ses pages (PageFragment). Et Android en a implémenté deux :

  • FragmentStatePagerAdapter : Cet adapter ne va PAS garder en mémoire toutes les pages affichées (fragments) après leur création. En effet, imaginez que vous développiez une application liseuse de Ebook contenant 1000 pages : Vous ne pouvez pas toutes les garder en mémoire ! Cet adapter se chargera donc de leur création/suppression à la volée (il n'en gardera que 3 en mémoire), optimisant ainsi les performances de votre application.

  • FragmentPagerAdapter : Cet adapter va garder en mémoire toutes les pages affichées (fragments) après leur création. Cela vous permettra une plus grande fluidité lors du défilement et de l'affichage de ces derniers, notamment si l'utilisateur doit faire des va-et-vient constants. Attention cependant à la complexité et au contenu de ces pages et leur nombre, afin de ne pas trop surcharger la mémoire.

Dans notre cas, nous allons créer et implémenter l'adapter FragmentPagerAdapter :

Fichier PageAdapter.java :

public class PageAdapter extends FragmentPagerAdapter {

    // 1 - Array of colors that will be passed to PageFragment
    private int[] colors;

    // 2 - Default Constructor
    public PageAdapter(FragmentManager mgr, int[] colors) {
        super(mgr);
        this.colors = colors;
    }

    @Override
    public int getCount() {
        return(5); // 3 - Number of page to show
    }

    @Override
    public Fragment getItem(int position) {
        // 4 - Page to return
        return(PageFragment.newInstance(position, this.colors[position]));
    }
}

Explications : Nous créons ici notre adapter, héritant de FragmentPagerAdapter  :

  • Ligne 1 : Nous définissons un tableau d'entiers, qui contiendra l'ensemble des couleurs de nos pages.

  • Ligne 2 : Nous créons un constructeur personnalisé qui nous permettra de passer le FragmentManager (tiens encore lui ! Normal, il est utilisé pour gérer les fragments au sein de la classe mère FragmentPagerAdapter) ainsi que notre tableau de couleurs.

  • Ligne 3 : Nous modifions également le nombre de pages (fragments) que l'on souhaite afficher dans notre ViewPager.

  • Ligne 4 : La méthode getItem( ) sera appelée dès qu'une page (fragment) demandera à être affichée.

 Bon du coup tout ça c'est bien beau, mais qui va lier toutes ces classes ensemble ? 

Notre activité bien sûr ! C'est son rôle de contrôleur non ? ;)

Fichier MainActivity.java :

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //3 - Configure ViewPager
        this.configureViewPager();
    }

    private void configureViewPager(){
        // 1 - Get ViewPager from layout
        ViewPager pager = (ViewPager)findViewById(R.id.activity_main_viewpager);
        // 2 - Set Adapter PageAdapter and glue it together
        pager.setAdapter(new PageAdapter(getSupportFragmentManager(), getResources().getIntArray(R.array.colorPagesViewPager)) {
        });
    }
}

Explications : Nous allons, dans notre activité MainActivity, récupérer notre ViewPager afin de lui configurer l'adapter PageAdapter, qui lui-même fera le pont (ou la liaison) avec nos différentes pages (PageFragment).

  • Ligne 1 : Récupération de la vue ViewPager depuis notre layout

  • Ligne 2 : Configuration de notre adapter PageAdapter dans notre ViewPager

  • Ligne 3 : Appel de notre méthode nouvellement créée configureViewPager( )

Nous avons aussi déclaré un tableau de couleurs, directement dans le fichier colors.xml que vous devez commencer à connaître :

Extrait du fichier colors.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    
    ...
    
    <!-- Array of colors that will be used by ViewPager as background colors -->
    <array name="colorPagesViewPager">
        <item>#EDD9CF</item>
        <item>#BED4D6</item>
        <item>#ADCEB7</item>
        <item>#F7CF8B</item>
        <item>#FD96A2</item>
    </array>
    
</resources>

Explications : Parfois, comme dans notre cas, il est nécessaire de déclarer un tableau contenant plusieurs valeurs, au lieu de les récupérer une par une dans notre code. Ici, une ligne de code suffira à récupérer l'ensemble des couleurs !

Voilàààààà ! :D Notre ViewPager est prêt à fonctionner correctement. Lancez l'application et n'hésitez pas encore une fois à jouer avec, afin de comprendre le fonctionnement de ce pattern dans les moindres détails...

Vous pouvez par exemple remplacer simplement FragmentPagerAdapter par FragmentStatePagerAdapter, et observer le résultat sur le cycle de vie des fragments ! ;)

Représentation finale du ViewPager
Représentation finale du ViewPager

Conclusion

Dans le prochain chapitre, nous allons améliorer un peu plus ce ViewPager, en lui ajoutant des Tabs ainsi que des pages différentes.

Vous pouvez retrouver le code du ViewPager terminé à ce lien.

Exemple de certificat de réussite
Exemple de certificat de réussite