Ajouter un Pull To Refresh avec SwipeRefreshLayout

Envie d’ajouter un effet Pull To Refresh à une liste ? Et bien sachez qu’il existe un composant natif à Android permettant d’ajouter cette fonctionnalité !

Pour ceux qui ignore ce qu’est un Pull To Refresh, je vais vous le montrer en image :

patterns_swipetorefresh_dont2_b3h7nn

Il s’agit donc d’ajouter un événement à une liste. Il s’active lorsque l’utilisateur est en haut de la liste et scroll vers le bas. Cette élément permet à l’utilisateur de mettre à jour les données de la liste de façon simple (par exemple, la liste d’email dans l’application Gmail).

Android Support V4

Avant de commencer à vous parler de cette vue, il faut que j’introduise une notion en Android : les bibliothèques de supports.

Comme vous pouvez le savoir, il existe une multitude de versions d’android, et à l’heure où je vous parle nous sommes sur Android Lolipop. Chaque version apporte son lot de nouveautés, de vues et d’outils, embarqués dans la nouvelle version du système d’exploitation installé sur nos smartphones. Le problème est la compatibilité avec les versions antérieures (par exemple supporter android à partir de 2.3).

En plus d’ajouter ces composants dans les nouvelles versions d’Android, ils seront publiés aussi dans des paquets nommés Support. Ce qui permet d’utiliser le composant quelques soit la version de l’appareil. Certains oseront dire que ça alourdit l’application, répondez leur que rien ne leur empêche de développer leur application en ne supportant que la dernière version d’Android, et donc de perdre la moitié des utilisateurs 😉

Utilisation

Nous allons donc commencer par importer cette librairie via Gradle :

compile 'com.android.support:support-v4:21.0.3'

L’utilisation se fait ensuite en 2 étapes, une partie dans le layout de notre écran, le reste dans notre code Java.

Layout

Partons d’un Layout simple, ne contenant qu’une ListView :

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

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

Afin d’ajouter la fonctionnalité de Pull To Refresh, il suffit juste de placer notre ListView dans un objet nommé  SwipeRefreshLayout. Comme dit précédemment, cet objet est inclus dans la librairie Support V4, nous devons donc l’utiliser avec son préfixe complet android.support.v4.widget.SwipeRefreshLayout

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

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.SwipeRefreshLayout>

</RelativeLayout>

Ajoutez un adapter qui affiche des chaînes de caractère (afin de visualiser plus facilement le résultat).

public class MainActivity extends ActionBarActivity {

    List strings = new ArrayList();

    ListView mListView;

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

        mListView = (ListView) findViewById(R.id.listView);

        for(int i=0;i<20;++i)
            strings.add("Element "+i);

        ArrayAdapter adapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, strings);
        mListView.setAdapter(adapter);
    }

}

Vous pouvez dès à présent essayer ce composant en compilant l’application et en le lançant sur votre smartphone.

 

Java

Vous aurez pu remarquer en testant le SwipeRefreshLayout qu’une fois cet element relâché, il tourne indéfiniment. En effet il faut qu’un contrôleur lui indique qu’il a finit de rafraichir le contenu de la ListView qu’il contient.

Comme toute vue, nous pouvons le récupérer notre avec son identifiant, avec la méthode findViewById

public class MainActivity extends ActionBarActivity {

    List strings = new ArrayList();

    ListView mListView;
    SwipeRefreshLayout mSwipeRefreshLayout;
    ArrayAdapter mAdapter;

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

        mListView = (ListView) findViewById(R.id.listView);
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);

        for(int i=0;i<20;++i)
            strings.add("Element "+i);

        mAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, strings);
        mListView.setAdapter(mAdapter);
    }

}

Si nous regardons la documentation officielle de cette vue, nous pouvons remarquer qu’elle possède les méthodes suivantes :

  • setColorSchemeColors(int… colors) : permet de modifier la couleur de la flèche qui tourne
  • setProgressBackgroundColor(int color) : permet de modifier la couleur de fond du cercle
  • setSize(int size) : permet de modifier la taille de notre flèche (DEFAULT ou LARGE)

Ces méthodes sont utilisées afin de modifier l’aspect de notre élément, mais intéressons nous plutôt au coté fonctionnel :

  • setRefreshing(true) : permet de lancer l’animation de mise à jour.
  • setRefreshing(false) : indique à la vue que le contenu de la ListView à été mise à jour
  • setOnRefreshListener(OnRefreshListener) : récupère les évènements lancés par notre SwipeRefreshLayout. Utilisé par notre Activity afin de savoir que l’utilisateur a effectué un SwipeToRefresh

Implémentons donc le OnRefreshListener dans notre Activity :

mSwipeRefreshLayout.setOnRefreshListener(this);

 

@Override
public void onRefresh() {
    //appellé lors de l'action Pull To Refresh
}

Je vais donc simuler une méthode longue comme un appel réseau qui aurait duré 2 secondes, ensuite ajouter des éléments à ma ListView puis indiquer à mon SwipeRefreshLayout que le la mise à jour a été effectuée . (Pour les puristes Android, il est préférable d’utiliser des AsyncTask)

Je vais simplement utiliser ici une méthode des vues nommée .PostDelayed(Runnable runnable, int delay) qui permet d’effectuer une action après delay millisecondes.

public class MainActivity extends ActionBarActivity implements SwipeRefreshLayout.OnRefreshListener {

    List strings = new ArrayList();

    ListView mListView;
    SwipeRefreshLayout mSwipeRefreshLayout;
    ArrayAdapter mAdapter;

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

        mListView = (ListView) findViewById(R.id.listView);
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
        mSwipeRefreshLayout.setOnRefreshListener(this);

        for(int i=0;i<20;++i)
            strings.add("Element "+i);

        mAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, strings);
        mListView.setAdapter(mAdapter);
    }

    @Override
    public void onRefresh() {
        //appellé lors de l'action Pull To Refresh

        mSwipeRefreshLayout.postDelayed(new Runnable() {
            @Override
            public void run() {
                //appellé après 2000 ms

                //vide la liste
                strings.clear();

                //puis ajoute les nouveaux elements
                for(int i=0;i<20;++i)
                    strings.add("NouvelElement "+i);

                //annonce à l'adapter que les données ont changés
                mAdapter.notifyDataSetChanged();

                //avertie le SwipeRefreshLayout que la mise à jour a été effectuée
                mSwipeRefreshLayout.setRefreshing(false);
            }
        },2000);
    }
}

Laisser un commentaire

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