Introduction aux Fragments

A Fragment is a piece of an application’s user interface or behavior that can be placed in an Activity

Ma traduction, avec quelques petits ajustements, donne :

Un fragment est un sous-contrôleur d’une activité, contenant une vue ainsi que son propre cycle de vie, capable d’être ajouté/retiré/déplacé d’une activité

Copyright Florent Champigny 😀

Regardons ensemble la différence entre les Activities et les Fragments

 ActivitéFragment
Doit être déclaré dans le ManifestOuiNon
Possède un cycle de vieOuiOui
Peux être utilisé dans une ActivitéOuiOui
Peux être utilisé dans un FragmentOuiNon
Sensible à l'orientationOuiOui
Affiche un LayoutOuiOui

Le principal avantage d’un fragment est le fait d’être facilement déplaçable. Vous avez donc tout interêt à mettre la logique d’une vue dans un fragment, au cas où vous voudriez déplacer cette vue, ou bien la réutiliser sur un autre écran (exemple : afficher une liste d’utilisateurs).

Utiliser les fragments depuis les layouts

Créer un fragment

Un fragment possède un cycle de vie différent des activités. Au lieu de déclarer une vue dans le onCreate() telle une activité (setContentView), le fragment possède 2 fonctions principales :

  • onCreateView(inflater,container,savedInstanceState) : demande d’inflater la vue à utiliser par ce fragment
  • onViewCreated(view,savedInstanceState) : le fragment possède enfin une vue, nous pouvons récupérer nos widgets (TextView, etc.) puis les modifier

MainFragment.java

public class MainFragment extends Fragment {

    TextView title;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main,container,false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        title = (TextView) view.findViewById(R.id.title);

        title.setText("Je suis un fragment");
    }
    
}

layout/fragment_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">

    <TextView
         android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center"/>

</LinearLayout>

Ajouter notre fragment à une activité

Nous pouvons inclure directement un fragment depuis les layouts, en utilisant la balise fragment, avec l’attribut android:name

layout/activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"     
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment         
        android:name="com.tutosandroidfrance.fragments.MainFragment"         
        android:layout_width="match_parent"         
        android:layout_height="match_parent">

</FrameLayout>

Il n’y a aucun code à ajouter dans votre activité

MainActivity.java

public class MainActivity extends AppCompatActivity {

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

}

device-2015-08-10-221139

Ajouter dynamiquement des fragments depuis Java

Il est possible d’ajouter les fragments directement depuis nos Activities, ce qui est plus simple, plus réutilisable et surtout plus modulable.

Il vous suffit de définir un layout (un FrameLayout fera l’affaire) qui pourra recevoir un fragment, puis d’utiliser le FragmentManager afin d’instancier puis d’injecter notre mimi contrôleur.

layout/activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"     
    android:layout_width="match_parent"     
    android:layout_height="match_parent">

    <FrameLayout         
        android:id="@+id/fragmentLayout"         
        android:layout_width="match_parent"         
        android:layout_height="match_parent"/>

</FrameLayout>

On utilise maintenant le FragmentManager dans notre Activity

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragmentLayout,new MainFragment())
                .commit();
    }

}

device-2015-08-10-221139

Envoyer des données à notre fragment

Prochaine étape, passer des données à notre fragment à sa création. SURTOUT, NE PAS REDEFINIR LE CONSTRUCTEUR !!!! (je vous aurais prévenu 🙂 )

newInstance

La norme Android veux que l’on ajoute une méthode statique newInstance, qui s’occupe dé gérer la création du fragment.
Nous allons passer nos données dans un bundle (et non intent) :

MainFragment.java

public class MainFragment extends Fragment {

    private static final String TITLE = "TITLE";

    public static MainFragment newInstance(String title) {
        MainFragment fragment = new MainFragment();
        Bundle args = new Bundle();
        args.putString(TITLE, title);
        fragment.setArguments(args);
        return fragment;
    }

    TextView title;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        title = (TextView) view.findViewById(R.id.title);

        if (getArguments() != null) {
            Bundle args = getArguments();
            if (args.containsKey(TITLE))
                title.setText(args.getString(TITLE));
        }
    }
}

device-2015-08-10-224654

Envoyer des données à notre activité

Cette partie se fait de plusieurs façons, je vais ici vous présenter la méthode “SDK”, si vous souhaitez la méthode simple, je vous invite à lire notre tutorial EventBus

1. Créer une interface MainFragmentCallBack

public class MainFragment extends Fragment {

    public interface MainFragmentCallback{
        void onTitleClicked();
    }

    ...
}

2. Implémenter cette interface dans notre activité

public class MainActivity extends AppCompatActivity implements MainFragment.MainFragmentCallback{

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

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragmentLayout, MainFragment.newInstance("Mon nouveau titre"))
                .commit();
    }

    @Override
    public void onTitleClicked() {
        //votre action, ici ce sera un simple Toast
        Toast.makeText(this,"Tu as clické !",Toast.LENGTH_SHORT).show();
    }
}

3. Récupérer le callback

On va utiliser le onAttach(activity) afin de récupérer notre activité en MainFragmentCallback, nous pourrons ensuite utiliser mainFragmentCallback.onTitleClicked() pour remonter notre information à l’activité. Bien penser à remettre mainFragmentCallback à null lorsque le fragment se détache.

public class MainFragment extends Fragment {

    public interface MainFragmentCallback {
        void onTitleClicked();
    }

    private static final String TITLE = "TITLE";

    public static MainFragment newInstance(String title) {
        MainFragment fragment = new MainFragment();
        Bundle args = new Bundle();
        args.putString(TITLE, title);
        fragment.setArguments(args);
        return fragment;
    }

    TextView title;
    MainFragmentCallback mainFragmentCallback;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof MainFragmentCallback)
            mainFragmentCallback = (MainFragmentCallback) activity;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mainFragmentCallback = null;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        title = (TextView) view.findViewById(R.id.title);

        Bundle args = getArguments();
        if (args != null) {
            if (args.containsKey(TITLE))
                title.setText(args.getString(TITLE));
        }

        title.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mainFragmentCallback != null)
                    mainFragmentCallback.onTitleClicked();
            }
        });
    }

}

device-2015-08-10-232735

Méthodes utiles

  • onActivityCreated appelée lorsque le fragment a bien été ajouté à l’activité
  • onAttached appelée lorsque le fragment est attaché à une activité
  • getActivity() retourne l’activité qui contient ce fragment, retourne null si elle est appelée avant le onActivityCreated/onAttached/onViewCreated
  • onDetach appelée lorsque le fragment est détaché de son activité
  • onCreate/onResume/onPause/onStart/onDestroy semblable au cycle de vie de l’activité
  • startActivity(intent) / startActivityForResult(intent)
  • onActivityResult(intent)

Dans un prochain tuto, nous verrons comment gérer plusieurs fragments par activité et bien plus !

En attendant, je vous invite à télécharger les sources de ce tuto, disponibles sur github
et surtout, n’hésitez pas à me poser des questions !

Laisser un commentaire

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