wake-up-neo.net

Wie aktualisiere ich eine GridView?

Ich habe ein GridView, das dem Google-Tutorial ziemlich ähnlich ist, mit der Ausnahme, dass ich die ImageViews zur Laufzeit hinzufügen möchte (über eine Subaktivität). Die Ergebnisse sind in Ordnung, aber das Layout der Ansicht ist fehlerhaft: Die GridView füllt nicht den Inhalt der übergeordneten Komponente. Was muss ich tun, um sie richtig zu entwerfen?

Hier der Code zum Hinzufügen der Kinder:

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());
    }
}

aktiviere Workbench, setDimension und Messen in der Workbench (LinearLayout über der 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);
}

Der ImageAdapter-Konstruktor:

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);
                }
            }
        }
    }
}

Und das XML-Layout:

<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

die GridView verfügt über eine invalidateViews () -Methode. 

wenn Sie diese Methode aufrufen: "Alle Ansichten, die neu erstellt und neu gezeichnet werden sollen." http://developer.Android.com/reference/Android/widget/GridView.html

ich denke, das ist was du brauchst :)

41
flyerz

Sie müssen dem Adapter zunächst mitteilen, dass sich die Daten geändert haben, und den Adapter erneut an das Raster setzen

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

Dies kann hilfreich sein .. Ich aktualisiere eine Rasteransicht der Miniaturansichten von Buchbildern, nachdem ein Löschen für ein Element ausgeführt wurde wie oben erwähnt funktionierte für mich nicht, wie es in meinem Adapter heißt.

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

Ich lade im Wesentlichen nur den Adapter neu und binde ihn an dieselbe Ansicht.

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

@flyerz @snagnever

Ihr habt es zusammen. Es sollte sein:

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

Dadurch wird der Adapter gekennzeichnet, dass seine Daten geändert wurden. Dieser wird dann bei jedem Aufruf der invalidateViews () - Methode an das Grid weitergegeben. 

Ich bin froh, dass ich diese Frage gefunden habe, weil ich nicht herausfinden konnte, wie Elemente nach dem Rendern in das Raster eingefügt werden.

10
Hobo

Keine dieser Antworten funktionierte tatsächlich für mich und ich musste alle zusammen zerdrücken. Um die GridView tatsächlich zu aktualisieren, müssen Sie Folgendes tun:

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

Ich hoffe, das hilft jedem, der die anderen Lösungen nicht zum Laufen bringt.

9
edwoollard

Sie sollten nicht invalidateViews und setAdapter aufrufen, um Ihren grid view zu aktualisieren. Dies ist keine gute Idee, Ihren grid view auf dem neuesten Stand zu halten. Wenn Sie auf diese Weise aktualisieren, würde dies viel Zeit und Speicher kosten. 

Wenn Sie die getView-Methode betrachten können, werden Sie feststellen, dass convertView nur einmal erstellt wird. Wenn Sie notifyDataChanged aufrufen, wird diese Ansicht aktualisiert. Wenn Sie dagegen invalidateViews aufrufen, werden zuvor erstellte Ansichten neu erstellt. Dies ist keine gute Lösung. 

Ihre getView-Methode wird aufgerufen, wenn Sie notifyDataChanged aufrufen. Ihre getView-Methode sollte daher etwa wie folgt aussehen.

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();

funktioniert möglicherweise nicht, nur weil die Daten für den Adapter veraltet sind (wenn Activity oder Fragment nicht zerstört wurde und zum Beispiel im hinteren Stack gestanden hat).

Wenn Sie also zuerst Daten aktualisieren, wird es danach funktionieren.

2
Andrey

In Ihrem Adapter:

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

Sie platzieren die GridView in com.unimelb.pt3.ui.TransparentPanel, die 10px groß ist.

  • Sie sollten px nicht verwenden, Sie sollten dp verwenden.
  • com.unimelb.pt3.ui.TransparentPanels Android:layout_height="10px" in Android:layout_height="fill_parent" ändern
0
Macarse