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 ?


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

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

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

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

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

Es este método que ayuda a conseguir el desplazamiento de GridView
Suchith
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.