A altura do GridView é cortada

124

Estou tentando exibir 8 itens dentro de um gridview. Infelizmente, a altura do gridview é sempre muito pequena, de modo que apenas mostra a primeira linha e uma pequena parte da segunda.

Configuração android:layout_height="300dp"faz funcionar. wrap_ contente fill_parentaparentemente não.

Minha visualização em grade:

<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" />

Meu recurso de itens:

<?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>

O problema não parece relacionado à falta de espaço vertical.

O que eu posso fazer ?

tacone
fonte

Respostas:

351

Após (muita) pesquisa, encontrei a excelente resposta de Neil Traft .

Adaptar seu trabalho para o trabalho GridViewfoi extremamente 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;
    }
}

Inclua-o no seu layout assim:

<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 fim, você só precisa pedir para expandir:

mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);
tacone
fonte
20
esta solução não economiza memória e o aplicativo falhará se as células forem imagens. Essa solução informa à exibição em rolagem qual é a altura da exibição em grade completa para que ela possa diminuir, mas o problema é que, para isso, ela renderiza tudo sem usar a reciclagem. Não havia mais de 200 itens funcionando.
Mariano Latorre
7
@amp Acho que existem casos úteis para isso. Se você possui um número limitado de itens para exibir em uma matriz 2D, usar esse tipo de GridView parece mais fácil do que tentar criar algum tipo de TableLayout dinâmico / personalizado, não?
Greg7gkb
5
Não funciona para mim, coloquei ExpandableHeightGridView em ScrollView, corta a última visualização.
Chirag Nagariya
3
@tacone Existem várias soluções melhores para esse tipo de problema prontamente disponíveis na estrutura, biblioteca de suporte e outro código-fonte aberto em toda a web, a mais fácil das quais pode ser um simples loop for puxando Views de um adaptador ou de outro local e adicionando-os a um GridLayout, (não GridView; GridLayout também está disponível na lib de suporte) TableLayout ou similar.
315 adamp
11
@adamp Se isso não é bom, por favor adicione a sua resposta com a melhor solução que você pode pensar
aleb
34

Depois de usar a resposta do @tacone e garantir que funcionasse, decidi tentar abreviar o código. Este é o meu resultado. PS: É o equivalente a ter a resposta booleana "expandida" nos tacones sempre definida como verdadeira.

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
fonte
Mas espere - isso ainda sofre com o problema do uso da memória; você não está mais reciclando, certo?
Fattie
6

Outra abordagem semelhante que funcionou para mim é calcular a altura de uma linha e, em seguida, com dados estáticos (você pode adaptá-lo para paginar), você pode calcular quantas linhas você possui e redimensionar a altura do GridView facilmente.

    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 depois de configurar o adaptador e quando o GridView for desenhado, ou você obterá height = 0.

gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (!gridViewResized) {
                    gridViewResized = true;
                    resizeGridView(gridView, numItems, numColumns);
                }
            }
        });
Pelanes
fonte
1
Isso funcionou bem para mim - estou usando um monte de GridViews dentro de um ListView. Ainda não tenho certeza se essa é uma má ideia - é necessário investigar o desempenho com um grande conjunto de dados. Mas, independentemente, obrigado pelo código. Eu acho que existe um erro de um por um - eu tive que usar #int rows = items / columns + 1;
277 Andrew Andrew
para abaixo Android OS 5.0 i get este errojava.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams
silverFoxA
Parâmetros ViewGroup.LayoutParams = gridView.getLayoutParams (); lança uma NullPointerException
Luke Allison
4

Os tacones encontrados respondem útil ... então eu o enviei para 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
fonte
1
Kudos cara. Funciona muito bem no xamarin.android
Suchith
0

Apenas calcule a altura para AT_MOST e defina-a como medida. Aqui o GridView Scroll não funcionará. Precisa usar a Visualização de rolagem vertical explicitamente.

 @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
fonte
É este método ajuda a obter a rolagem para GridView
Suchith