Redessiner une seule ligne dans une vue de liste

Est-il possible de redessiner une seule ligne dans un ListView ? J’ai un ListView avec des lignes qui sont LinearLayout s. J’écoute un changement de préférence et j’ai parfois besoin de changer une seule View dans LinearLayout d’une seule ligne. Est-il possible de le faire redessiner 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.

Comme l’a expliqué Romain Guy lors de la session Google I / O , le moyen le plus efficace de ne mettre à jour qu’une seule vue dans une vue liste est la suivante (celle-ci met à jour l’intégralité 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 la target est un élément de l'adaptateur.

Ce code récupère le ListView , puis navigue dans les vues actuellement affichées, compare l’élément target vous recherchez à chaque élément de vue affiché et, si votre cible fait partie de ces éléments, obtenez la vue englobante et exécutez l’adaptateur getView() sur cette vue pour rafraîchir l'affichage.

Comme une note d' invalidate() ne fonctionne pas comme certaines personnes l'attendent et n'actualisera pas la vue comme le fait getView() , notifyDataSetChanged() reconstruira la liste entière et finira par 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 lui suffit 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 faisons confiance.

Le view.invalidate() n’a pas fonctionné pour moi. Mais cela fonctionne comme un charme:

Supposons que vous mettez à jour la position ” position ” dans la rangée. Le if éviter les redessins bizarres, comme le texte qui danse 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(); } }); } 

Romain Guy a répondu à cette question lors de la vidéo “Google IO 2010 Le monde de ListView” à 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, cela devrait marcher, et je pense que nous pouvons lui faire confiance.

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

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

Placez une balise sur la ligne que vous souhaitez mettre à jour. Lorsque vous souhaitez redessiner cette vue ou cette ligne spécifique, procédez comme suit:

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

et alors

 View v = lv.findViewWithTag(tagobject); 

et puis vous faites ce que vous voulez avec la vue.