Question

I ont un GridView dont les éléments sont basés sur un FrameLayout contenant un ImageView et un CheckedTextView. Le fichier xml pour le FrameLayout est la suivante:

<FrameLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:id="@+id/gridImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="false">
</ImageView>
<CheckedTextView
android:id="@+id/imageTick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal|bottom"
android:checkMark="@drawable/icon"
android:checked="false"
android:visibility="invisible"
>
</CheckedTextView>
</FrameLayout>

EDIT: Ceci est la méthode de getView() de l'adaptateur i utilisation pour chaque élément:

public View getView(int position, View convertView, ViewGroup parent) {
        Log.d("getView()", position+"");
        View v;
        ImageView imageView;
        if(convertView == null) {

            v = LayoutInflater.from(mContext).inflate(R.layout.photo_text_view, null);
            v.setLayoutParams(new GridView.LayoutParams(100,100));
        }
        else
        {
            v = convertView;

        }
        imageView = (ImageView) v.findViewById(R.id.image);
        imageView.setImageBitmap(mThumbsIds.get().get(position));

        v.setPadding(8, 8, 8, 8);
        return v;
    }

Dans ma classe d'activité, je charge un menu contextuel et une fois que je sélectionne une option je fais le CheckedTextView visible pour cet élément de GridView comme ceci:

GridView gridView = (GridView) findViewById(R.id.gridview);
    View selected =gridView.getChildAt(position);
    CheckedTextView selectedCheck = (CheckedTextView)selected.findViewById(R.id.imageTick);
    selectedCheck.setChecked(true);
    selectedCheck.setVisibility(View.VISIBLE);

Donc deux choses peuvent potentiellement se produire à partir de ce point:

1) Disons que j'ai choisi l'élément à la position 0, la CheckedTextView devient visible, mais quand je défiler vers le bas mon GridView, un autre élément (par exemple la position 17) a son CheckedTextView aswell visible. Cela continue sur des éléments aléatoires que je défilement vers le bas vers le bas.

2) Si je prends un élément vers le bas, revenir en arrière jusqu'au sommet, et exécutez l'une des méthodes pour rendre les invisibles de CheckedTextView, un NullPointerException est jeté pour l'élément au fond. Cela se produit à ce stade. View selected =gridView.getChildAt(position); où sélectionné devient nulle

ce qui se passe ici? Pourquoi ces années de CheckedTextView aléatoires deviennent visibles et pourquoi dois-je obtenir des exceptions?

Était-ce utile?

La solution

Les problèmes se situent dans la façon dont vous suivre les articles cochés:

GridView gridView = (GridView) findViewById(R.id.gridview);
View selected =gridView.getChildAt(position);
CheckedTextView selectedCheck = (CheckedTextView)selected.findViewById(R.id.imageTick);
selectedCheck.setChecked(true);
selectedCheck.setVisibility(View.VISIBLE);

1) getChildAt vous ne donnera pas la vue correcte si vous avez fait défiler dans le contenu et vous êtes indexation par la position de l'adaptateur. Lorsque vous faites référence une vue active dans un GridView ou ListView que vous voulez faire quelque chose comme ceci:

final int index = position - gridView.getFirstVisiblePosition();
View selected = gridView.getChildAt(index);

La raison en est que votre GridView ne conserve que des vues de l'enfant pour les éléments de l'adaptateur qu'il est actuellement d'affichage. Il ne peut avoir des vues de l'enfant pour les éléments 4 à 23 si des éléments 0 à 3 ont été hors du défiler en haut plus tôt.

Ceci est la raison pour laquelle vous obtenez des exceptions lorsque vous faites View selected =gridView.getChildAt(position); une vue pour cette position n'existe pas réellement quand il est hors de l'écran, alors retourne getChildAt null.

2) Lorsqu'un ListView ou GridView a son contenu ou le changement dont il a besoin par ailleurs de re-présentation de ses vues de l'enfant, il le fait en réappairant les vues existantes en utilisant le paramètre convertView à votre adaptateur. Votre carte ajuste jamais l'état vérifié de votre point de vue de l'objet, donc une vue vérifiée peut être réutilisé pour un élément devrait décocher plus tard.

Pour résoudre cela, vous devez avoir votre modèle de données que vos cadeaux adaptateur suivre l'état vérifié de vos articles plutôt que de compter sur les vues d'éléments pour le faire. Cela signifie que votre adaptateur doit toujours vérifier / définir l'état contrôlé de l'élément dans getView. Il peut ressembler à ceci:

imageView = (ImageView) v.findViewById(R.id.image);
imageView.setImageBitmap(mThumbsIds.get().get(position));

CheckedTextView checkView = (CheckedTextView) v.findViewById(R.id.imageTick);

if (mData.isItemChecked(position)) {
    checkView.setChecked(true);
    checkView.setVisibility(View.VISIBLE);
} else {
    checkView.setVisibility(View.GONE);
}

Ensuite, lorsque votre option est sélectionnée qui devrait changer l'état contrôlé d'un élément, au lieu du code extrait ci-dessus faire quelque chose comme:

data.setItemChecked(position, true);
adapter.notifyDataSetChanged();

notifyDataSetChanged() racontera l'GridView qu'il devrait re-lier les vues de l'objet, qui aura votre méthode de getView Rénovez des états vérifiés correctement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top