Fragment

01 – Comprendre le Fragment

Présentation du cours

Ce cours suppose que vous avez des bases en Android.

Sans ces bases, il sera difficile de continuer.

Fragment se traduit par « fragment » ou « morceau ».

En réalité, « fragment » est le terme le plus juste.

C’est un morceau d’interface utilisateur intégré dans une Activité.

Il permet d’exploiter plus rationnellement et efficacement l’espace des grands écrans.

C’est donc parfait pour les tablettes.

Il ressemble beaucoup à une Activité : il possède une mise en page et son propre cycle de vie.

On peut le voir comme une mini Activité.

Lorsqu’on développe une application d’actualités,

sur un écran de téléphone, on pourrait concevoir comme ceci :

une Activité de liste, et en cliquant on arrive à une Activité de détail de l’article.

Mais sur une tablette, faire la même chose laisserait de grands espaces vides, ce qui n’est pas idéal.

Une meilleure solution est de diviser la liste et le détail dans deux fragments au sein d’une même Activité.

Créer un émulateur de tablette

Pour tester correctement notre application sur tablette, nous allons créer un émulateur de tablette.

02 – Premier exemple avec Fragment

Ajouter deux fragments dans une Activité et les faire partager l’espace équitablement.

Ajoutez un nouveau projet appelé FragmentFirst.

Ajoutez deux mises en page : une pour le fragment de gauche

newlist.xml

et une pour le fragment de droite, newdetail.xml.

Fragment de gauche

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/buttondialog"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Guerre commerciale Chine-États-Unis 2018" />
</LinearLayout>Langage du code : HTML, XML (xml)

Fragment de droite

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#0ddb97"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Contenu de l'article contenu de l'article" />
</LinearLayout>Langage du code : HTML, XML (xml)

Ajouter la classe Fragment

Ajoutez un NewListFragment.

Héritez de android.support.v4.app.Fragment.

Puis redéfinissez la méthode onCreateView pour que ce fragment utilise le xml newlist.

public class NewListFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.newlist,container,false);
        return view;
    }
}Langage du code : PHP (php)

Ajoutez le fragment de détail de la même manière.

NewDetailFragment hérite également de

android.support.v4.app.Fragment.

public class NewDetailFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.newdetail,container,false);
        return view;
    }
}Langage du code : PHP (php)

Appeler les fragments dans la vue principale de l’Activité

Utilisez l’attribut android:name= »com.foxdevelop. » pour définir quel fragment utiliser.

Lors de l’ajout d’un fragment dans la vue principale, l’id est obligatoire.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/newlist_fragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:name="com.foxdevelop.www.fragmentfirst.NewListFragment"
        />
    <fragment
        android:id="@+id/newdetail_fragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"
        android:name="com.foxdevelop.www.fragmentfirst.NewDetailFragment"
        />
</LinearLayout>Langage du code : HTML, XML (xml)

03 – Ajouter des fragments dynamiquement

La vraie puissance des fragments réside dans leur capacité à être ajoutés dynamiquement à une Activité pendant l’exécution.

En ajoutant dynamiquement des fragments selon la situation, nous pouvons créer des interfaces beaucoup plus variées.

Par exemple, dans notre application d’actualités, certains articles sont des images, d’autres du texte, d’autres des vidéos. On peut charger différentes mises en page de fragments selon le type d’article.

Ajoutons une vue new_picture.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/birdsee"
        />
</LinearLayout>Langage du code : HTML, XML (xml)

Pour le distinguer, il affiche simplement une image.

Ajouter la classe de fragment pour l’image

public class NewImageFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.new_picture,container,false);
        return view;
    }
}Langage du code : PHP (php)

Utiliser FrameLayout dans la vue principale

Ici, nous utilisons une FrameLayout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/newlist_fragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:name="com.foxdevelop.www.fragmentfirst.NewListFragment"
        />

    <FrameLayout
        android:id="@+id/framelayout"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"
        ></FrameLayout>
</LinearLayout>Langage du code : HTML, XML (xml)

Ajouter deux boutons à gauche

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/buttondialog"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Guerre commerciale Chine-États-Unis 2018" />
    <Button
        android:id="@+id/buttonpicture"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Actualité image" />
</LinearLayout>Langage du code : HTML, XML (xml)

Ajouter des événements aux boutons dans l’Activité principale

En ajoutant des événements de clic aux boutons, nous pouvons charger dynamiquement différents fragments selon le bouton pressé.

package com.foxdevelop.www.fragmentfirst;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Lier les événements aux deux boutons
        Button b1 = (Button)findViewById(R.id.buttonarticle);
        b1.setOnClickListener(this);
        Button b2 = (Button)findViewById(R.id.buttonpicture);
        b1.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        // Charger différents fragments selon le bouton
        switch (view.getId())
        {
            case R.id.buttonarticle:
                setFragement(new NewDetailFragment());
                break;
            case R.id.buttonpicture:
                setFragement(new NewImageFragment());
                break;
            default:
                break;
        }
    }

    // Cette méthode définit le fragment pour le FrameLayout
    public void setFragement(Fragment fragement) {
        FragmentManager fragementManager = getSupportFragmentManager();
        // Démarrer une transaction
        android.support.v4.app.FragmentTransaction fragmentTransaction = fragementManager.beginTransaction();
        fragmentTransaction.replace(R.id.framelayout,fragement);// Définit le FrameLayout pour utiliser le fragment passé
        fragmentTransaction.commit();
    }
}Langage du code : JavaScript (javascript)

04 – Utiliser la pile de retour (back stack) avec les fragments

Nous avons expliqué ce qu’est la pile de retour dans le cours de base.

Dans l’exemple précédent, quand on appuie sur le bouton retour, l’application quitte directement l’Activité principale et ferme le programme. Ce n’est pas ce qu’on veut. On voudrait que le bouton retour ramène au fragment précédent.

Faire en sorte que les fragments prennent en charge la pile de retour est en fait très simple.

Il suffit d’ajouter la transaction à la pile de retour.

// Cette méthode définit le fragment pour le FrameLayout
public void setFragement(Fragment fragement) {
    FragmentManager fragementManager = getSupportFragmentManager();
    // Démarrer une transaction
    android.support.v4.app.FragmentTransaction fragmentTransaction = fragementManager.beginTransaction();
    fragmentTransaction.replace(R.id.framelayout,fragement);// Définit le FrameLayout pour utiliser le fragment passé
    fragmentTransaction.addToBackStack(null);// Ajoute la transaction à la pile de retour
    fragmentTransaction.commit();
}Langage du code : JavaScript (javascript)

05 – Communication entre Fragment et Activité

Les fragments sont intégrés dans les activités, mais en réalité leur relation n’est pas si étroite.

Notre Fragment et notre Activité existent en fait comme des classes indépendantes.

Il n’y a pas de moyen direct pour eux de communiquer.

Pour faciliter la communication,

FragmentManager fournit une méthode similaire à findViewById, utilisée pour obtenir une instance de fragment à partir de la mise en page.

getFragmentManager android.support.v4.app.Fragment

nécessite un cast. Ce point n’est pas mentionné dans le livre.

Si vous avez importé le package android.support.v4.app.Fragment (c’est-à-dire le package v4)

import android.support.v4.app.Fragment;

alors pour obtenir le FragmentManager, vous devez utiliser

FragmentManager fm = getSupportFragmentManager();

Le fragment correspondant doit aussi importer le bon package !

// Obtenir l'instance du fragment dans la méthode onCreate de l'Activité
NewListFragment newListFragment = (NewListFragment)getSupportFragmentManager().findFragmentById(R.id.newlist_fragment);
Toast.makeText(this, newListFragment.getId()+"xxxx",Toast.LENGTH_LONG).show();Langage du code : JavaScript (javascript)

Obtenir l’Activité depuis le fragment

// Obtenir l'Activité depuis le fragment
MainActivity mainActivity = (MainActivity) getActivity();
Toast.makeText(getContext(), mainActivity.getTitle(),Toast.LENGTH_LONG).show();Langage du code : JavaScript (javascript)

Vous pouvez appeler la méthode getActivity().

06 – Cycle de vie du Fragment

Le cycle de vie du fragment est fondamentalement le même que celui de l’Actité.

Les fragments ont aussi quatre états.

En cours d’exécution, En pause, Arrêté, Détruit.

1. État en cours d’exécution : le fragment est visible et l’Activité à laquelle il appartient est en cours d’exécution, donc le fragment est aussi actif.

2. État en pause

Lorsqu’une autre Activité qui ne remplit pas tout l’écran est ajoutée au sommet de la pile, le fragment visible qu’elle gère passe à l’état en pause.

3. État arrêté

Lorsqu’une Activité passe à l’état arrêté, ses fragments associés passent aussi à l’état arrêté. Ou bien, si vous utilisez les méthodes remove ou replace de FragmentTransaction pour retirer un fragment d’une Activité, et que vous avez appelé addToBackStack avant de valider la transaction, il passera aussi à l’état arrêté.

En résumé, un fragment à l’état arrêté est invisible pour l’utilisateur et peut être récupéré par le système à tout moment.

4. État détruit

Les fragments dépendent toujours des Activités. Donc quand une Activité est détruite, ses fragments associés passent aussi à l’état détruit. Ou bien, si vous utilisez remove ou replace pour retirer un fragment sans avoir appelé addToBackStack avant validation, il passera aussi à l’état détruit.

Comme pour les Activités, Fragment fournit aussi une série de méthodes de rappel couvrant chaque étape du cycle de vie. Presque tout ce qu’une Activité a, un Fragment l’a aussi.

En même temps, Fragment propose aussi quelques méthodes de rappel supplémentaires.

Fragment

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *