159 votes

Comment mettre à jour dynamiquement un ListView sur Android

Sur Android, comment puis-je créer un ListView qui filtre en fonction de l'entrée de l'utilisateur, où les éléments affichés sont mis à jour dynamiquement en fonction de la valeur de TextView ?

Je cherche quelque chose comme ça :

-------------------------
| Text View             |
-------------------------
| Élément de liste      |
| Élément de liste      |
| Élément de liste      |
| Élément de liste      |
|                       |
|                       |
|                       |
|                       |
-------------------------

286voto

Hamy Points 5700

Tout d'abord, vous devez créer une mise en page XML qui contient à la fois un EditText et un ListView.

Cela disposera tout correctement, avec un joli EditText au-dessus du ListView. Ensuite, créez une ListActivity comme vous le feriez normalement, mais ajoutez un appel setContentView() dans la méthode onCreate() afin d'utiliser notre mise en page récemment déclarée. Rappelez-vous que nous avons spécialement identifié le ListView avec android:id="@android:id/list". Cela permet à la ListActivity de savoir quel ListView nous voulons utiliser dans notre mise en page déclarée.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.filterable_listview);

        setListAdapter(new ArrayAdapter(this,
                       android.R.layout.simple_list_item_1, 
                       getStringArrayList());
    }

Maintenant, en exécutant l'application, vous devriez voir votre ListView précédent, avec une jolie boîte au-dessus. Pour que cette boîte fasse quelque chose, nous devons prendre l'entrée et filtrer la liste. Alors que beaucoup de gens ont essayé de le faire manuellement, la plupart des classes d'adaptateur ListView viennent avec un objet Filter qui peut être utilisé pour effectuer le filtrage automatiquement. Nous devons simplement rediriger l'entrée de l'EditText vers le Filter. Il s'avère que c'est assez facile. Pour faire un test rapide, ajoutez cette ligne à votre appel onCreate()

adapter.getFilter().filter(s);

Remarquez que vous devrez enregistrer votre ListAdapter dans une variable pour que cela fonctionne - j'ai sauvegardé mon ArrayAdapter précédent dans une variable appelée 'adapter'.

La prochaine étape consiste à obtenir l'entrée de l'EditText. Cela nécessite un peu de réflexion. Vous pourriez ajouter un OnKeyListener à votre EditText. Cependant, cet auditeur ne reçoit que certains événements de touches. Par exemple, si un utilisateur entre 'wyw', le texte prédictif recommandera probablement 'œil'. Jusqu'à ce que l'utilisateur choisisse soit 'wyw' soit 'œil', votre OnKeyListener ne recevra pas d'événement de touche. Certains peuvent préférer cette solution, mais je l'ai trouvée frustrante. Je voulais chaque événement de touche, pour avoir le choix de filtrer ou non. La solution est un TextWatcher. Créez simplement et ajoutez un TextWatcher à l'EditText, et transmettez une demande de filtrage au Filter de ListAdapter à chaque changement de texte. N'oubliez pas de supprimer le TextWatcher dans OnDestroy ! Voici la solution finale :

private EditText filterText = null;
ArrayAdapter adapter = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.filterable_listview);

    filterText = (EditText) findViewById(R.id.search_box);
    filterText.addTextChangedListener(filterTextWatcher);

    setListAdapter(new ArrayAdapter(this,
                   android.R.layout.simple_list_item_1, 
                   getStringArrayList());
}

private TextWatcher filterTextWatcher = new TextWatcher() {

    public void afterTextChanged(Editable s) {
    }

    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }

    public void onTextChanged(CharSequence s, int start, int before,
            int count) {
        adapter.getFilter().filter(s);
    }

};

@Override
protected void onDestroy() {
    super.onDestroy();
    filterText.removeTextChangedListener(filterTextWatcher);
}

10voto

j7nn7k Points 5019

Exécuter le programme provoquera une fermeture forcée.

J'ai échangé la ligne :

android:id="@+building_list/search_box"

avec

android:id="@+id/search_box"

cela pourrait-il être le problème? Que signifie '@+building_list'?

4voto

cV2 Points 2073

J'avais un problème avec le filtrage, les résultats ont été filtrés, mais pas restaurés !

donc avant le filtrage (démarrage de l'activité) j'ai créé une sauvegarde de la liste.. (juste une autre liste, contenant les mêmes données)

lors du filtrage, le filtre et l'adaptateur de liste sont connectés à la liste principale.

mais le filtre lui-même utilisait les données de la liste sauvegardée.

cela a assuré dans mon cas que la liste était mise à jour immédiatement et même en supprimant des caractères de terme de recherche la liste est restaurée avec succès dans tous les cas :)

merci pour cette solution de toute façon.

1voto

Leander Points 223

Que diriez-vous d'un filtre insensible à la casse ?

Vous penseriez que ce serait facile, mais le filtre intégré ne semble pas le comprendre. Ce qui rend le filtre intégré un peu moins utile.

Il n'y a pas non plus de setFilter, ni d'usuable propriétés pour l'objet filtre. Donc nous devons sous-classer Listview pour créer un filtre simple insensible à la casse ?

Parfois, Android peut être un peu trop compliqué.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X