web-dev-qa-db-fra.com

Redessiner une seule ligne dans une liste

Est-il possible de redessiner une seule ligne dans un ListView? J'ai un ListView avec des lignes qui sont LinearLayouts. J'écoute un changement de préférence et parfois je n'ai besoin de changer qu'un View à l'intérieur du LinearLayout d'une seule ligne. Existe-t-il un moyen de redessiner cette ligne sans appeler listview.notifyDatasetChanged()?

J'ai essayé d'appeler view.invalidate () sur la vue (à l'intérieur de LinearLayout) mais cela ne redessine pas la ligne.

40
Falmarri

Comme Romain Guy expliqué un pe lors de la session Google I/O , le moyen le plus efficace de mettre à jour une seule vue dans une vue de liste est quelque chose comme ceci (celui-ci mettre à jour l'ensemble des données View):

ListView list = getListView();
int start = list.getFirstVisiblePosition();
for(int i=start, j=list.getLastVisiblePosition();i<=j;i++)
    if(target==list.getItemAtPosition(i)){
        View view = list.getChildAt(i-start);
        list.getAdapter().getView(i, view, list);
        break;
    }

En supposant que target est un élément de l'adaptateur.

Ce code récupère le ListView, puis parcourez les vues actuellement affichées, comparez l'élément target que vous recherchez avec chaque élément de vue affiché, et si votre cible est parmi celles-ci, obtenez la vue englobante et exécutez l'adaptateur getView() sur cette vue pour actualiser l'affichage.

Comme une note latérale invalidate() ne fonctionne pas comme certaines personnes s'y attendent et ne rafraîchira pas la vue comme getView() le fait, notifyDataSetChanged() reconstruira toute la liste et finira appeler getview() pour chaque élément affiché et invalidateViews() affectera également un groupe.

Une dernière chose, on peut également obtenir des performances supplémentaires s'il n'a besoin que de changer un enfant d'une vue de ligne et non la ligne entière comme le fait getView. Dans ce cas, le code suivant peut remplacer list.getAdapter().getView(i, view, list); (exemple pour modifier un texte TextView):

((TextView)view.findViewById(R.id.myid)).setText("some new text");

En code, nous avons confiance.

106
GriffonRL

La view.invalidate() ne fonctionnait pas pour moi. Mais cela fonctionne comme un charme:

supposons que vous mettez à jour la position "position" dans la ligne. Les if évitent les trucs redessinés étranges, comme la danse de texte lorsque vous mettez à jour une ligne qui n'est pas à l'écran.

            if (position >= listView.getFirstVisiblePosition()
                && position <= listView.getLastVisiblePosition()) {

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            listView.invalidateViews();
                        }
                    });
            }
6
Felipe

Romain Guy a répondu à cette question sur "Google IO 2010 The world of ListView" Video à l'heure exacte à laquelle cette question a été posée: http://www.youtube.com/ watch? feature = player_detailpage & v = wDBM6wVEO70 # t = 3149s

Donc selon Romain Guy, ça devrait marcher, et je pense qu'on peut lui faire confiance.

La raison pour laquelle votre vue n'est pas redessinée est un peu mystérieuse. Essayez peut-être de désactiver toutes les options de cache disponibles dans listView

setAnimationCacheEnabled(false);
setScrollingCacheEnabled(false);
setChildrenDrawingCacheEnabled(false);
setChildrenDrawnWithCacheEnabled(false);
3
jptsetung

Mettez une balise sur la ligne que vous souhaitez mettre à jour. Lorsque vous souhaitez redessiner cette vue ou cette ligne spécifique, faites

ListView lv = (ListView)findViewById(....)

puis

View v = lv.findViewWithTag(tagobject);

puis vous faites ce que vous voulez avec la vue.

0
user590849