web-dev-qa-db-fra.com

Comment actualiser un GridView?

J'ai un GridView qui est assez similaire au tutoriel de Google, sauf que je veux ajouter ImageViews au moment de l'exécution (via une sous-activité). Les résultats sont corrects, mais la présentation de la vue est perturbée: le GridView ne remplit pas le contenu de son parent, que dois-je faire pour le concevoir correctement?

Voici le code pour ajouter les enfants:

public void initializeWorkbench(GridView gv, Vector<String> items) {
        Prototype.workbench.setDimension(screenWidth, divider.height()+workbenchArea.height());
        Prototype.workbench.activateWorkbench();
        // this measures the workbench correctly
        Log.d(Prototype.TAG, "workbench width: "+Prototype.workbench.getMeasuredWidth());
        // 320
        Log.d(Prototype.TAG, "workbench height: "+Prototype.workbench.getMeasuredHeight());
        // 30
        ImageAdapter imgAdapter = new ImageAdapter(this.getContext(), items);
        gv.setAdapter(imgAdapter);
        gv.measure(screenWidth, screenHeight);
        gv.requestLayout();
        gv.forceLayout();
        Log.d(Prototype.TAG, "gv width: "+gv.getMeasuredWidth());
        // 22
        Log.d(Prototype.TAG, "gv height: "+gv.getMeasuredHeight());
        // 119
        Prototype.workbench.setDimension(screenWidth, divider.height()+workbenchArea.height());
    }
}

activateWorkbench, setDimension et measure dans le workbench (LinearLayout au-dessus du GridView):

public void activateWorkbench() {
    if(this.equals(Prototype.workbench)) {
        this.setOrientation(VERTICAL);
        show = true;
        measure();
    }
}

public void setDimension(int w, int h) {
    width = w;
    height = h;
    this.setLayoutParams(new LinearLayout.LayoutParams(width, height));
    this.invalidate();
}

private void measure() {
    if (this.getOrientation() == LinearLayout.VERTICAL) {
        int h = 0;
        int w = 0;
        this.measureChildren(0, 0);
        for (int i = 0; i < this.getChildCount(); i++) {
            View v = this.getChildAt(i);
            h += v.getMeasuredHeight();
            w = (w < v.getMeasuredWidth()) ? v.getMeasuredWidth() : w;
        }
        if (this.equals(Prototype.tagarea))
            height = (h < height) ? height : h;
        if (this.equals(Prototype.tagarea))
            width = (w < width) ? width : w;
    }
    this.setMeasuredDimension(width, height);
}

Le constructeur ImageAdapter:

public ImageAdapter(Context c, Vector<String> items) {
    mContext = c;

    boolean mExternalStorageAvailable = false;
    boolean mExternalStorageWriteable = false;
    String state = Environment.getExternalStorageState();

    if (Environment.MEDIA_MOUNTED.equals(state)) {
        // We can read and write the media
        mExternalStorageAvailable = mExternalStorageWriteable = true;
    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        // We can only read the media
        mExternalStorageAvailable = true;
        mExternalStorageWriteable = false;
    } else {
        // Something else is wrong. It may be one of many other states, but
        // all we need
        // to know is we can neither read nor write
        mExternalStorageAvailable = mExternalStorageWriteable = false;
    }

    if (mExternalStorageAvailable && mExternalStorageWriteable) {
        for (String item : items) {
            File f = new File(item);
            if (f.exists()) {
                try {
                    FileInputStream fis = new FileInputStream(f);
                    Bitmap b = BitmapFactory.decodeStream(fis);
                    bitmaps.add(b);
                    files.add(f);
                } catch (FileNotFoundException e) {
                    Log.e(Prototype.TAG, "", e);
                }
            }
        }
    }
}

Et la mise en page XML:

<LinearLayout   xmlns:Android="http://schemas.Android.com/apk/res/Android" 
            Android:layout_width="fill_parent" 
            Android:layout_height="fill_parent"
                Android:orientation="vertical"
                Android:gravity="bottom"

                Android:paddingLeft="0px"
                Android:paddingTop="0px"
                Android:paddingRight="0px">

    <com.unimelb.pt3.ui.TransparentPanel
            Android:id="@+id/workbench" 
            Android:layout_width="fill_parent"
            Android:layout_height="10px"
            Android:paddingTop="0px"
            Android:paddingLeft="0px"
            Android:paddingBottom="0px"
            Android:paddingRight="0px">

        <GridView xmlns:Android="http://schemas.Android.com/apk/res/Android" 
            Android:id="@+id/gridview"
            Android:layout_width="fill_parent" 
            Android:layout_height="fill_parent"
            Android:columnWidth="90dp"
            Android:numColumns="auto_fit"
            Android:verticalSpacing="10dp"
            Android:horizontalSpacing="10dp"
            Android:stretchMode="columnWidth"
            Android:gravity="center" />

    </com.unimelb.pt3.ui.TransparentPanel>

</LinearLayout>
29
Daniel

le GridView a une méthode invalidateViews (). 

lorsque vous appelez cette méthode: "toutes les vues à reconstruire et à redessiner". http://developer.Android.com/reference/Android/widget/GridView.html }

je pense que c'est ce dont vous avez besoin :)

41
flyerz

Vous devez d'abord demander à l'adaptateur de vous informer que les données ont été modifiées, puis définissez à nouveau l'adaptateur sur la grille.

adapter.notifyDataChanged();
grid.setAdapter(adapter);
33
snagnever

Cela peut être utile . J'actualise une grille d'images miniatures de livre après la suppression d'un élément . Using adapter.notifyDataChanged (); comme mentionné ci-dessus n'a pas fonctionné pour moi comme il est appelé dans mon adaptateur.

//this is a call that retrieves cached data.
//your constructor can be designed and used without it.
final Object data = getLastNonConfigurationInstance();

Je ne fais que recharger l’adaptateur et le lier à la même vue.

//reload the adapter
adapter = new BooksAdapter(MyBooks.this, MyBooks.this, data, show_collection );
grid.invalidateViews();
grid.setAdapter(adapter);
17
Rickey

@flyerz @snagnever

Ensemble, vous l'avez compris. CA devrait etre:

adapter.notifyDataChanged();
grid.invalidateViews();

Cela indiquera à l'adaptateur que ses données ont été modifiées, ce qui sera ensuite propagé à la grille après l'appel de la méthode invalidateViews (). 

Je suis content d'avoir trouvé cette question, car je ne savais pas comment ajouter des éléments à la grille après son rendu.

10
Hobo

Aucune de ces réponses n'a réellement fonctionné pour moi et j'ai dû les écraser toutes ensemble. Pour que le GridView soit mis à jour, procédez comme suit:

 adapter.notifyDataChanged();
 grid.invalidateViews();
 grid.setAdapter(adapter);

J'espère que cela aide tous ceux qui ne peuvent pas utiliser les autres solutions.

9
edwoollard

Vous ne devez pas appeler invalidateViews et setAdapter pour actualiser votre grid view. Ce n’est pas une bonne idée de garder votre grid view mis à jour, si vous mettez à jour de cette façon, cela coûterait beaucoup de temps et de mémoire. 

Si vous avez une chance de regarder la méthode getView, vous verrez que convertView est créé une seule fois. Lorsque vous appelez notifyDataChanged, cette vue sera mise à jour. Considérant que si vous appelez invalidateViews, les vues créées précédemment seront recréées. Ce n'est pas une bonne solution. 

Votre méthode getView est appelée lorsque vous appelez notifyDataChanged. Donc, votre méthode getView devrait ressembler au code ci-dessous.

public List list;

public class SimpleItemViewHolder extends Object
{
    public TextView textView;
    public ImageView imageView;
}

public View getView(int position, View convertView, ViewGroup parent){

    View itemView = convertView;
    SimpleItemViewHolder viewHolder;

    if(convertView==null)
    {
        viewHolder = (SimpleItemViewHolder)itemView.getTag();

    }else{
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        itemView = inflater.inflate(R.layout.layout_name, null);
        TextView labelField = (TextView) itemView.findViewById(R.id.label_field);
        labelField.setText(list.get(position).Name);
        //Typeface boldFont = Typeface.createFromAsset(context.getAssets(), "fonts/Font-Bold.ttf");
        //labelField.setTypeface(boldFont);

        ImageView imageView = (ImageView) itemView.findViewById(R.id.image_view);
        //Bitmap bitmap = init your bitmap here;
        //imageView.setImageBitmap(bitmap);  

        viewHolder = new SimpleItemViewHolder();
        viewHolder.imageView = imageView;
        viewHolder.textView = labelField;
        itemView.setTag(viewHolder);

    }

    //don't create new views, instead use previous ones and update them.
    viewHolder.textView.setText(list.get(position).Name);
    //viewHolder.imageView.setImageBitmap(your_bitmap);  
    return itemView;
}
5
aytek
adapter.notifyDataChanged();

peut ne pas fonctionner simplement parce que les données de l'adaptateur sont obsolètes (si Activity ou un fragment n'a pas été détruit et s'est assis dans la pile arrière, par exemple).

Donc, si tout d’abord actualise les données, alors après cela fonctionnera.

2
Andrey

Dans votre adaptateur:

class MAdapter extends BaseAdapter{
   List<Objects> mObjects;
...

 public void clearAdapter(){
        mObjects.clear();
    }

 public void addNewValues(List<Objects> mObjects){
        this.mObjects = mObjects;
    }

...

}


adapter.clearAdapter(); // clear old values
adapter.addNewValues(MObjects);
adapter.notifyDataChanged();
0
Gilberto Ibarra

Vous placez la GridView dans com.unimelb.pt3.ui.TransparentPanel qui est 10px haut.

  • Vous ne devriez pas utiliser px, vous devriez utiliser dp.
  • Remplacez com.unimelb.pt3.ui.TransparentPanel de Android:layout_height="10px" par Android:layout_height="fill_parent"
0
Macarse