Sous Android, comment puis-je utiliser un ListView
qui filtre en fonction des entrées de l'utilisateur, les éléments affichés étant mis à jour de manière dynamique en fonction de la valeur TextView
?
Je cherche quelque chose comme ça:
-------------------------
| Text View |
-------------------------
| List item |
| List item |
| List item |
| List item |
| |
| |
| |
| |
-------------------------
Tout d'abord, vous devez créer une mise en page XML comportant à la fois un EditText et un ListView.
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="fill_parent"
Android:layout_height="fill_parent"
Android:orientation="vertical" >
<!-- Pretty hint text, and maxLines -->
<EditText Android:id="@+building_list/search_box"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:hint="type to filter"
Android:inputType="text"
Android:maxLines="1"/>
<!-- Set height to 0, and let the weight param expand it -->
<!-- Note the use of the default ID! This lets us use a
ListActivity still! -->
<ListView Android:id="@Android:id/list"
Android:layout_width="fill_parent"
Android:layout_height="0dip"
Android:layout_weight="1"
/>
</LinearLayout>
Cela mettra tout en place correctement, avec un Nice EditText au-dessus de ListView. Ensuite, créez une ListActivity comme vous le feriez normalement, mais ajoutez un appel setContentView()
dans la méthode onCreate()
afin que nous utilisions notre layout récemment déclaré. Rappelez-vous que nous avons identifié le ListView
spécialement, avec Android:id="@Android:id/list"
. Ceci permet au ListActivity
de savoir quel ListView
nous voulons utiliser dans notre présentation déclarée.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.filterable_listview);
setListAdapter(new ArrayAdapter<String>(this,
Android.R.layout.simple_list_item_1,
getStringArrayList());
}
Lancer l'application maintenant devrait montrer votre précédent ListView
, avec une belle boîte ci-dessus. Pour que cette boîte de dialogue fasse quelque chose, nous devons prendre son entrée et lui faire filtrer la liste. Bien que beaucoup de gens aient essayé de le faire manuellement, les classes la plupartListView
Adapter
sont fournies avec un objet Filter
qui peut être utilisé pour effectuer les opérations suivantes: filtrer automatiquement. Nous avons juste besoin de canaliser l'entrée du EditText
dans le Filter
. Il s'avère que c'est assez facile. Pour exécuter un test rapide, ajoutez cette ligne à votre appel onCreate()
adapter.getFilter().filter(s);
Notez que vous aurez besoin de sauvegarder votre ListAdapter
dans une variable pour que cela fonctionne. J'ai sauvegardé mon ArrayAdapter<String>
Précédemment dans une variable appelée "adaptateur".
La prochaine étape consiste à obtenir les données de EditText
. Cela prend un peu de réflexion. Vous pouvez ajouter une OnKeyListener()
à votre EditText
. Cependant, cet écouteur ne reçoit que certains événements clés. Par exemple, si un utilisateur entre "wyw", le texte prédictif recommandera probablement "œil". Tant que l'utilisateur n'aura pas choisi 'wyw' ou 'eye', votre OnKeyListener
ne recevra pas d'événement de clé. Certains préfèrent peut-être cette solution, mais je l’ai trouvée frustrante. Je voulais chaque événement clé, donc j'avais le choix de filtrer ou non. La solution est un TextWatcher
. Il vous suffit de créer et d'ajouter un TextWatcher
au EditText
et de transmettre le ListAdapter
Filter
une demande de filtre à chaque changement de texte. N'oubliez pas de supprimer le TextWatcher
dans OnDestroy()
! Voici la solution finale:
private EditText filterText = null;
ArrayAdapter<String> 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<String>(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);
}
l'exécution du programme provoquera une fermeture forcée.
J'ai échangé la ligne:
Android: id = "@ + building_list/search_box"
avec
Android: id = "@ + id/search_box"
est-ce que cela pourrait être le problème? A quoi sert '@ + building_list'?
j'ai eu un problème avec le filtrage, les résultats ont été filtrés, mais non restauré!
donc avant de filtrer (début d'activité) j'ai créé une sauvegarde de 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 primaire.
mais le filtre lui-même a utilisé les données de la liste sauvegardée.
dans mon cas, cela garantissait que la liste était mise à jour immédiatement et même après suppression des caractères de recherche-terme, la liste était restaurée avec succès dans tous les cas :)
merci pour cette solution quand même.