La altura de la vista de cuadrícula se corta

124

Estoy tratando de mostrar 8 elementos dentro de una vista de cuadrícula. Lamentablemente, la altura de la vista de cuadrícula siempre es demasiado pequeña, por lo que solo muestra la primera fila y una pequeña parte de la segunda.

La configuración lo android:layout_height="300dp"hace funcionar. wrap_ contenty fill_parentaparentemente no.

Mi vista de cuadrícula:

<GridView
    android:id="@+id/myId"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:horizontalSpacing="2dp"
    android:isScrollContainer="false"
    android:numColumns="4"
    android:stretchMode="columnWidth"
    android:verticalSpacing="20dp" />

Mi recurso de artículos:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:minHeight="?android:attr/listPreferredItemHeight" >

    <ImageView
        android:id="@+id/appItemIcon"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:src="@android:drawable/ic_dialog_info"
        android:scaleType="center" />      

    <TextView
        android:id="@+id/appItemText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="My long application name"
        android:gravity="center_horizontal"
        android:textAppearance="?android:attr/textAppearanceSmall" />

</LinearLayout>

El problema no parece estar relacionado con la falta de espacio vertical.

Que puedo hacer ?

tacone
fuente

Respuestas:

351

Después de (demasiado) investigación, me topé con la excelente respuesta de Neil Traft .

Adaptar su trabajo para el GridViewha sido muy fácil.

ExpandableHeightGridView.java:

package com.example;
public class ExpandableHeightGridView extends GridView
{

    boolean expanded = false;

    public ExpandableHeightGridView(Context context)
    {
        super(context);
    }

    public ExpandableHeightGridView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ExpandableHeightGridView(Context context, AttributeSet attrs,
            int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public boolean isExpanded()
    {
        return expanded;
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // HACK! TAKE THAT ANDROID!
        if (isExpanded())
        {
            // Calculate entire height by providing a very large height hint.
            // View.MEASURED_SIZE_MASK represents the largest height possible.
            int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
                    MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);

            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();
        }
        else
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    public void setExpanded(boolean expanded)
    {
        this.expanded = expanded;
    }
}

Inclúyalo en su diseño de esta manera:

<com.example.ExpandableHeightGridView
    android:id="@+id/myId"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:horizontalSpacing="2dp"
    android:isScrollContainer="false"
    android:numColumns="4"
    android:stretchMode="columnWidth"
    android:verticalSpacing="20dp" />

Por último, solo necesita pedirle que se expanda:

mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);
tacone
fuente
20
Esta solución no es eficiente en memoria y la aplicación se bloqueará si las celdas son imágenes. Esta solución le dice a la vista de desplazamiento cuál es la altura de la vista de cuadrícula completa para que pueda bajar, pero el problema es que al hacerlo representa todo sin usar el reciclaje. No más de 200 artículos podrían funcionar.
Mariano Latorre
77
@adamp Creo que hay casos útiles para esto. Si tiene un número limitado de elementos para mostrar en una matriz 2d, usar este tipo de GridView parece más fácil que intentar crear algún tipo de TableLayout personalizado / dinámico, ¿no?
greg7gkb
55
No funciona para mí, he puesto ExpandableHeightGridView debajo de ScrollView, corta la última vista.
Chirag Nagariya
3
@tacone Hay una serie de mejores soluciones para este tipo de problema fácilmente disponibles en el marco, la biblioteca de soporte y otro código fuente abierto en la web, la más fácil de las cuales puede ser una simple vista de extracción de bucle desde un adaptador u otro lugar y agregándolos a un GridLayout, (no a GridView; GridLayout también está disponible en la biblioteca de soporte) TableLayout o similar.
adamp
11
@adamp Si esto no es bueno, por favor agregue su respuesta con la mejor solución que pueda pensar
aleb
34

Después de usar la respuesta de @tacone y asegurarme de que funcionara, decidí intentar acortar el código. Este es mi resultado. PD: Es el equivalente a tener el booleano "expandido" en la respuesta de tacones siempre establecido en verdadero.

public class StaticGridView extends GridView {

    public StaticGridView(Context context) {
        super(context);
    }

    public StaticGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public StaticGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST));
        getLayoutParams().height = getMeasuredHeight();
    }
}
Jacob R
fuente
Pero espere, esto todavía sufre el problema del uso de memoria; ya no estás reciclando ¿verdad?
Fattie
6

Otro enfoque similar que funcionó para mí es calcular la altura de una fila y luego con datos estáticos (puede adaptarlos para paginar) puede calcular cuántas filas tiene y cambiar el tamaño de la altura de GridView fácilmente.

    private void resizeGridView(GridView gridView, int items, int columns) {
    ViewGroup.LayoutParams params = gridView.getLayoutParams();
    int oneRowHeight = gridView.getHeight();
    int rows = (int) (items / columns);
    params.height = oneRowHeight * rows;
    gridView.setLayoutParams(params);
}

Use este código después de configurar el adaptador y cuando se dibuje GridView o obtendrá height = 0.

gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (!gridViewResized) {
                    gridViewResized = true;
                    resizeGridView(gridView, numItems, numColumns);
                }
            }
        });
Pelanes
fuente
1
Esto funcionó bien para mí: estoy usando un montón de GridViews dentro de un ListView. No estoy seguro de si esa es una mala idea todavía o no: es necesario investigar el rendimiento con un gran conjunto de datos. Pero independientemente, gracias por el código. Sin embargo, creo que hay un error off-by-one - tuve que usarloint rows = items / columns + 1;
Andrew
para Android OS 5.0 a continuación recibo este errorjava.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams
silverFoxA
ViewGroup.LayoutParams params = gridView.getLayoutParams (); lanza una NullPointerException
Luke Allison el
4

Los tacones encontrados responden útil ... así que lo porté a C # (Xamarin)

public class ExpandableHeightGridView: GridView
{
    bool _isExpanded = false;

    public ExpandableHeightGridView(Context context) : base(context)
    {            
    }

    public ExpandableHeightGridView(Context context, IAttributeSet attrs) : base(context, attrs)
    {            
    }

    public ExpandableHeightGridView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
    {            
    }

    public bool IsExpanded
    {
        get { return _isExpanded; }

        set { _isExpanded = value;  }
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // HACK! TAKE THAT ANDROID!
        if (IsExpanded)
        {
            // Calculate entire height by providing a very large height hint.
            // View.MEASURED_SIZE_MASK represents the largest height possible.
            int expandSpec = MeasureSpec.MakeMeasureSpec( View.MeasuredSizeMask, MeasureSpecMode.AtMost);
            base.OnMeasure(widthMeasureSpec,expandSpec);                

            var layoutParameters = this.LayoutParameters;
            layoutParameters.Height = this.MeasuredHeight;
        }
        else
        {
            base.OnMeasure(widthMeasureSpec,heightMeasureSpec);    
        }
    }
}
spaceMonster
fuente
1
Felicitaciones amigo. Funciona muy bien en xamarin.android
Suchith
0

Simplemente calcule la altura para AT_MOST y configúrelo a medida. Aquí GridView Scroll no funcionará así. Necesita usar la Vista de desplazamiento vertical explícitamente.

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     int heightSpec;

     if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {

         heightSpec = MeasureSpec.makeMeasureSpec(
                        Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
     }
     else {
         // Any other height should be respected as is.
         heightSpec = heightMeasureSpec;
     }

     super.onMeasure(widthMeasureSpec, heightSpec);
 }
Uday Sravan K
fuente
Es este método que ayuda a conseguir el desplazamiento de GridView
Suchith