Android: accéder aux vues enfants à partir d'un ListView

108

J'ai besoin de connaître la position des pixels d'un élément dans une liste qui a été affichée à l'aide d'un fichier ListView. Il semble que je devrais obtenir l'un des TextView, puis l'utiliser getTop(), mais je ne peux pas comprendre comment obtenir une vue enfant d'un ListView.

Mise à jour: les enfants de ViewGroupne correspondent pas 1 à 1 avec les éléments de la liste, pour un ListView. Au lieu de cela, les ViewGroupenfants de correspondent uniquement aux vues qui sont visibles actuellement. Donc getChildAt()opère sur un index qui est interne au ViewGroupet n'a pas nécessairement quoi que ce soit à voir avec la position dans la liste que le ListViewutilise.

laque
la source

Réponses:

215

Voir: Android ListView: obtenir l'index des données de l'élément visible et le combiner avec une partie de la réponse de Feet ci-dessus, peut vous donner quelque chose comme:

int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
  Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
  return;
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
View wantedView = listView.getChildAt(wantedChild);

L'avantage est que vous n'effectuez pas d'itérations sur les enfants de ListView, ce qui pourrait nuire aux performances.

Joe
la source
10
Excellente réponse, mais ne fonctionne pas tout à fait correctement lorsque vous avez des vues d'en-tête dans votre liste. La tâche à firstPositiondevrait être int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();de résoudre ce problème.
pospi
@pospi: merci, bon point! J'ai mis à jour ma réponse pour en tenir compte.
Joe
Bonne réponse et fonctionne dans la majorité des cas, mais je ne comprends pas pourquoi vous pensez que les vues enfants apparaissent dans l'ordre dans lequel elles sont dans le tableau des vues enfants. Puisque les vues peuvent être réutilisées, comment pouvons-nous être sûrs que la première vue ne représente pas la dernière vue visible?
Victor Denisov
2
@VictorDenisov: cela ne peut se produire que sur le thread de l'interface utilisateur; par conséquent, le thread d'interface utilisateur sera bloqué pendant l'exécution de ce code, ainsi les vues enfants sont stationnaires et ne seront pas modifiées. ListViewest déjà la manipulation « déplacer » les vues de l' enfant autour après le recyclage de vieux convertViews, etc, de sorte que vous pouvez être assuré que ListView.getChildAt(0) est en fait le point de vue d' abord attaché de l'adaptateur. Il peut ne pas être entièrement visible (et peut même ne pas être visible du tout, selon le ListViewseuil de «visibilité» avant de recycler une vue qu'il considère comme «défilée hors de la vue»)
Joe
1
@Matheus ce n'est pas ainsi que fonctionne Android ListView. Si l'élément de liste est hors écran, son point de vue a déjà été recyclée et réutilisée pour l' un des autres éléments de liste qui sont à l' écran. Vous devriez repenser la façon dont vous utilisez ListView si c'est une exigence.
Joe
17

Ce code est plus simple à utiliser:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if(rowView != null)
        {
           // Your code here
        }
Kalimah
la source
9
ne fonctionne pas toujours. getChildAt compte à partir de la première ligne visible, et non du haut des données.
SteelBytes
13
L'argument ViewID est déroutant. C'est un indice (ou une position). L'ID de vue est un entier complètement arbitraire généré par l'outil aapt.
Johan Pelgrim
6

Une recherche rapide dans la documentation de la classe ListView a révélé les méthodes getChildCount () et getChildAt () héritées de ViewGroup. Pouvez-vous les parcourir en utilisant ces derniers? Je ne suis pas sûr mais ça vaut le coup d'essayer.

Trouvé ici

Pieds
la source
1
J'ai essayé ceci, pour faire des sélections. Cela fonctionne généralement, mais il y a parfois des erreurs ponctuelles et ce n'est pas fiable. Je ne le recommanderais pas.
Timmmm
Merci Timmmm, je ne l'avais pas vraiment essayé, je l'ai trouvé dans la documentation.
Pieds
5
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
        View v;
        int count = parent.getChildCount();
        v = parent.getChildAt(position);
        parent.requestChildFocus(v, view);
        v.setBackground(res.getDrawable(R.drawable.transparent_button));
        for (int i = 0; i < count; i++) {
            if (i != position) {
                v = parent.getChildAt(i);
                v.setBackground(res.getDrawable(R.drawable.not_clicked));
            }
        }
    }
});

Fondamentalement, créez deux Drawables - un transparent et un autre de la couleur souhaitée. Demander le focus à la position cliquée ( int positiontelle que définie) et changer la couleur de ladite ligne. Puis parcourez le parent ListViewet modifiez toutes les autres lignes en conséquence. Cela tient compte du moment où un utilisateur clique sur listviewplusieurs fois. Cela se fait avec une mise en page personnalisée pour chaque ligne du ListView. (Très simple, créez simplement un nouveau fichier de mise en page avec un TextView- ne définissez pas le focus ou le cliquable!).

Aucun adaptateur personnalisé requis - utiliser ArrayAdapter

Nous s
la source
getChildAt est relatif aux éléments défilés actuels. Cela cessera de fonctionner si vous faites défiler un peu votre liste.
nurettin
4
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);
Milaaaad
la source
1
Élaborer un peu
innoSPG
-9

Cela suppose que vous connaissez la position de l'élément dans ListView:

  View element = listView.getListAdapter().getView(position, null, null);

Ensuite, vous devriez pouvoir appeler getLeft () et getTop () pour déterminer les éléments sur la position de l'écran.

Jasonhudgins
la source
43
getView()est appelé en interne par ListView, lors du remplissage de la liste. Vous ne devez pas l' utiliser pour obtenir la vue à cette position dans la liste, car l'appel getView()avec null pour le convertViewfait que l'adaptateur gonfle une nouvelle vue à partir de la ressource de mise en page de l'adaptateur (n'obtient pas la vue qui est déjà affichée).
Joe
1
La position paire correspond à une position sur l'écran visuel, et non à la position de la source de données de l'adaptateur.
Vikas
@jasonhudgins C'est la méthode que j'utilise depuis, je pensais que c'était la meilleure, mais quand j'essaie de rendre invisible une barre de progression dans la vue enfant, mais à la place, toutes les barres de progression de listvew sont invisibles ........ tout en toutes les réponses acceptées ont fait l'affaire
Edijae Crusar