2010-12-14 25 views
27

Tengo un GridView que es bastante similar al tutorial de Google, excepto que quiero agregar ImageViews en tiempo de ejecución (a través de una subactividad). Los resultados están bien, pero el diseño de la Vista está mal: GridView no llena el contenido de su elemento primario, ¿qué debo hacer para diseñarlo correctamente?Cómo actualizar un GridView?

Aquí el código de la adición de los niños:

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 y medida en el banco de trabajo (LinearLayout por encima de la 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); 
} 

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

Y el diseño 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> 

Respuesta

0

Usted está colocando el GridView dentro de com.unimelb.pt3.ui.TransparentPanel que es 10px alto.

  • No debe usar px, debe usar dp.
  • Cambio com.unimelb.pt3.ui.TransparentPanel 's android:layout_height="10px" a android:layout_height="fill_parent"
+0

Lo cambié, pero no ayuda. El problema no es la altura de GridView, que se encuentra en tamaño completo en TransparentPanel y tiene una barra de desplazamiento para el contenido de gran tamaño, pero el ancho. Esto es solo 22, aunque sus LayoutParams son fill_parent y TransparentPanel tiene un ancho de 320. Creo que necesito actualizar/actualizar el proceso de diseño, pero no sé cómo hacerlo correctamente. – Daniel

40

GridView tiene un método invalidateViews().

cuando llama a este método: "todas las vistas deben reconstruirse y volver a dibujarse". http://developer.android.com/reference/android/widget/GridView.html

Creo que esto es lo que usted necesita :)

+0

Solo el subproceso original que creó una jerarquía de vista puede tocar sus vistas. Cuando refresca una vista de cuadrícula, a menudo lo hace porque está recuperando información de la web, en cuyo caso no será así. – AndrewPK

+0

Esto no forzó un redibujado de la vista para mí. –

30

Debe, dicen primero el adaptador para notificar que los datos han cambiado y configurar el adaptador de nuevo a la red

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

Esto funcionó para mí, pero con 'adapter.notifyDataSetChanged()' en la primera línea, mientras que no necesitaba la segunda línea. De acuerdo con http://developer.android.com/reference/android/widget/BaseAdapter.html, el primero obliga a la (s) vista (s) para actualizar. ¡Gracias! –

10

@flyerz @snagnever

Juntos ustedes lo tienen. Debe ser:

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

Esta bandera voluntad el adaptador que sus datos ha cambiado, que luego se propaga a la red cada vez después de que el método invalidateViews() es llamado.

Me alegro de haber encontrado esta pregunta porque no pude encontrar la manera de agregar elementos a la cuadrícula después de haber sido renderizada.

16

Esto puede ser útil. Renuevo una vista en cuadrícula de miniaturas de imágenes de libros después de que se ejecuta una eliminación en un elemento. Usando adapter.notifyDataChanged(); como se mencionó anteriormente no funcionó para mí, ya que se llama en mi adaptador.

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

Básicamente, solo vuelvo a cargar el adaptador y lo ato a la misma vista.

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

¡gracias! tu método funcionó para mí mi adaptador utiliza elementos aleatorios y para que pueda volver a crearlos todo el tiempo que necesitaba para crear un nuevo objeto adaptador. me salvaste mucho tiempo de búsqueda. muchas gracias. – ufk

9

Ninguna de estas respuestas funcionó realmente para mí y tuve que mezclarlas todas juntas.Para conseguir realmente el GridView para actualizar, lo que necesita hacer esto:

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

la esperanza que esto ayude a que no pudieron conseguir las otras soluciones para trabajar.

+0

¿No tienes que crear un nuevo adaptador con los nuevos valores? –

0

En su adaptador:

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

puede no funciona simplemente porque los datos para el adaptador es rancio (si la actividad o el fragmento no fue destruido y se han sentado en la pila de vuelta, por ejemplo).

Por lo tanto, si primero se actualizan los datos, entonces estarán funcionando.

4

No debe llamar al invalidateViews y setAdapter para actualizar su grid view. Esta no es una buena idea para mantener su grid view actualizado, si actualiza de esa manera, costaría mucho tiempo y memoria.

Si tiene la oportunidad de ver el método getView, verá que convertView se crea solo una vez. Cuando llame al notifyDataChanged, actualizará esta vista. Mientras que si llama al invalidateViews, se recrearán las vistas creadas anteriormente. Esta no es una buena solución.

Se llama al método getView cuando llama al notifyDataChanged. Por lo tanto, su método getView debe parecerse al código siguiente.

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í. Esta es la teoría. ¿Y qué haces si el grid no actualiza su diseño cuando convertViews cambia sus tamaños? –

+1

@EmrysMyrooin Creo que no cambiaría nada si cambia el tamaño de una celda. Solo necesitas configurar los elementos de diseño de itemView. También puede ser útil anular y llamar al método 'onMeasure' de gridview. – aytek

+0

No, no está funcionando. Si una altura de elementoView cambia a lo largo del tiempo, GridView no detectará los cambios, incluso con un 'adapter.notifySetChanges()' o un 'gridView.invalidateViews()'. Tal vez funciona con la anulación de 'onMeasure', pero simplemente no uso implementar un GridView personalizado para lograr un comportamiento tan básico ... –

Cuestiones relacionadas