2010-12-14 18 views
27

Ho un GridView che è molto simile al tutorial di Google, ad eccezione del fatto che voglio aggiungere ImageViews su runtime (tramite un'attivita '). I risultati sono ok, ma il layout della vista è incasinato: GridView non riempie il contenuto del suo genitore, cosa devo fare per progettarlo correttamente?Come aggiornare un GridView?

Ecco il codice di aggiungere i bambini:

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 e misura nel workbench (LinearLayout sopra il 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); 
} 

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

E il layout 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> 

risposta

0

Si sta posizionando il GridView all'interno di com.unimelb.pt3.ui.TransparentPanel che è 10px alto.

  • Non è necessario utilizzare px, è necessario utilizzare dp.
  • Change com.unimelb.pt3.ui.TransparentPanel s' android:layout_height="10px" al android:layout_height="fill_parent"
+0

L'ho modificato, ma non aiuta. Il problema non è l'altezza del GridView, che è collocato a grandezza piena in TransparentPanel e ha una barra di scorrimento per contenuti di grandi dimensioni, ma la larghezza. Questo è solo 22, anche se i suoi LayoutParam sono fill_parent e TransparentPanel ha una larghezza di 320. Penso di aver bisogno di aggiornare/aggiornare il processo di layout, ma non so come farlo correttamente. – Daniel

40

GridView ha un metodo invalidateViews().

quando si chiama questo metodo: "tutte le viste da ricostruire e ridisegnare". http://developer.android.com/reference/android/widget/GridView.html

Penso che questo sia quello che ti serve :)

+0

Solo il thread originale che ha creato una gerarchia di viste può toccare le sue viste. Quando stai aggiornando una griglia, lo stai facendo spesso perché stai recuperando informazioni dal web, nel qual caso non sarà così. – AndrewPK

+0

Questo non ha imposto il ridisegno della visualizzazione per me. –

30

Devi, in primo luogo dire l'adattatore per notificare che i dati è cambiato e impostare di nuovo l'adattatore alla rete

adapter.notifyDataChanged(); 
grid.setAdapter(adapter); 
+9

Questo ha funzionato per me, ma con 'adapter.notifyDataSetChanged()' nella prima riga, mentre non avevo bisogno della seconda linea. Secondo http://developer.android.com/reference/android/widget/BaseAdapter.html, il primo forza le View da aggiornare. Grazie! –

10

@flyerz @snagnever

Insieme avete capito. Dovrebbe essere:

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

Questo flag volontà l'adattatore suoi dati è cambiato, che sarà poi propagato alla rete ogni volta dopo il metodo invalidateViews() è chiamato.

Contento Ho trovato questa domanda perché non riuscivo a capire come aggiungere elementi alla griglia dopo il suo rendering.

16

Potrebbe essere utile. Aggiornamento di una griglia delle miniature delle immagini dei libri dopo l'eliminazione di un elemento. utilizzando adapter.notifyDataChanged(); come detto sopra non ha funzionato per me come viene chiamato nel mio adattatore.

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

In sostanza, mi basta ricaricare l'adattatore e collegarlo alla stessa vista.

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

grazie! il tuo metodo ha funzionato per me. il mio adattatore usa elementi casuali e per ricrearli tutto il tempo necessario per creare un nuovo oggetto adattatore. mi hai risparmiato un sacco di tempo per la ricerca. molte grazie. – ufk

9

Nessuna di queste risposte ha funzionato per me e ho dovuto mescolarle tutte insieme.Per ottenere effettivamente il GridView per aggiornare, è necessario fare questo:

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

Spero che questo aiuti chi non ha potuto ottenere le altre soluzioni per lavorare.

+0

Non devi creare un nuovo adattatore con i nuovi valori? –

0

l'adattatore:

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(); 
2
adapter.notifyDataChanged(); 

potrebbe non funziona solo perché i dati per l'adattatore è stantio (se l'attività o il frammento non è stato distrutto e sono stati seduti nello stack posteriore, per esempio).

Quindi, se in primo luogo aggiornare i dati, quindi dopo che funzionerà.

4

Non è necessario chiamare invalidateViews e setAdapter per aggiornare grid view. Questa non è una buona idea per mantenere aggiornato il tuo grid view, se si aggiorna in questo modo sarebbe costato un sacco di tempo e di memoria.

Se si ha la possibilità di guardare il metodo getView, si vedrà che convertView viene creato una sola volta. Quando chiami notifyDataChanged, aggiornerà questa visualizzazione. Mentre se si chiama invalidateViews, le visualizzazioni create in precedenza verranno ricreate. Questa non è una buona soluzione.

Il metodo getView viene chiamato quando si chiama notifyDataChanged. Quindi il tuo metodo getView dovrebbe apparire come il seguente codice.

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; 
} 
+0

Sì. Questa è teoria. E cosa fai se la Grid non aggiorna il suo layout quando convertViews cambia le loro dimensioni? –

+1

@EmrysMyrooin Penso che non cambierebbe nulla se si modifica la dimensione di una cella. Hai solo bisogno di impostare i layoutparam dell'oggetto itemView. Può anche essere utile ignorare e chiamare il metodo 'onMeasure' di gridview. – aytek

+0

No, non funziona. Se l'altezza di itemView cambia nel tempo, GridView non rileverà le modifiche, anche con un 'adapter.notifySetChanges()' o un 'gridView.invalidateViews()'. Forse funziona con l'override di 'onMeasure', ma non voglio implementare un GridView personalizzato solo per ottenere un comportamento di base ... –

Problemi correlati