La hauteur de Gridview est coupée

125

J'essaye d'afficher 8 éléments dans une grille. Malheureusement, la hauteur de la vue de la grille est toujours trop petite, de sorte qu'elle ne montre que la première ligne et une petite partie de la seconde.

Le réglage le android:layout_height="300dp"fait fonctionner. wrap_ contentetfill_parent apparemment pas.

Ma vue grille:

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

Ma ressource d'articles:

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

Le problème ne semble pas lié à un manque d'espace vertical.

Que puis-je faire ?

tacone
la source
Est-ce que cela répond à votre question? Comment avoir un GridView qui adapte sa hauteur lorsque des éléments sont ajoutés
Shivam Agarwal

Réponses:

351

Après (trop) de recherches, je suis tombé sur l'excellente réponse de Neil Traft .

Adapter son travail pour le GridViewa été extrêmement facile.

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

Incluez-le dans votre mise en page comme ceci:

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

Enfin, il vous suffit de lui demander de s'étendre:

mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);
tacone
la source
20
cette solution n'est pas efficace en mémoire et l'application plantera si les cellules sont des images. Cette solution indique à la scrollview quelle est la hauteur de la grille complète pour qu'elle puisse descendre, mais le problème est que pour ce faire, elle rend tout sans utiliser de recyclage. Pas plus de 200 articles pourraient fonctionner.
Mariano Latorre
7
@adamp Je pense qu'il existe des cas utiles pour cela. Si vous avez un nombre limité d'éléments à afficher dans un tableau 2d, utiliser ce type de GridView semble plus facile que d'essayer de créer une sorte de TableLayout personnalisée / dynamique, non?
greg7gkb
5
Ne fonctionne pas pour moi, j'ai mis ExpandableHeightGridView sous ScrollView, il coupe la dernière vue.
Chirag Nagariya
3
@tacone Il existe un certain nombre de meilleures solutions pour ce type de problème facilement disponibles dans le framework, la bibliothèque de support et d'autres codes open source sur le Web, la plus simple d'entre elles pouvant être une simple extraction de vues en boucle for à partir d'un adaptateur ou ailleurs et en les ajoutant à un GridLayout, (pas GridView; GridLayout est également disponible dans la bibliothèque de support) TableLayout ou similaire.
adamp
11
@adamp Si ce n'est pas bon, veuillez ajouter votre réponse avec la meilleure solution à laquelle vous pouvez penser
aleb
34

Après avoir utilisé la réponse de @tacone et m'être assuré que cela fonctionnait, j'ai décidé d'essayer de raccourcir le code. C'est mon résultat. PS: C'est l'équivalent d'avoir la réponse booléenne "développée" dans les tacones toujours mise à true.

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
la source
Mais attendez - cela souffre encore du problème de l'utilisation de la mémoire; tu ne recycles plus, non?
Fattie
6

Une autre approche similaire qui a fonctionné pour moi consiste à calculer la hauteur d'une ligne, puis avec des données statiques (vous pouvez l'adapter à la pagination), vous pouvez calculer le nombre de lignes que vous avez et redimensionner facilement la hauteur de GridView.

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

Utilisez ce code après avoir défini l'adaptateur et lorsque le GridView est dessiné ou vous obtiendrez height = 0.

gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (!gridViewResized) {
                    gridViewResized = true;
                    resizeGridView(gridView, numItems, numColumns);
                }
            }
        });
Pélanes
la source
1
Cela a bien fonctionné pour moi - j'utilise un tas de GridViews dans un ListView. Je ne sais pas si c'est encore une mauvaise idée ou non - il faut étudier les performances avec un grand ensemble de données. Mais peu importe, merci pour le code. Je pense qu'il y a une erreur ponctuelle - j'ai dû utiliserint rows = items / columns + 1;
Andrew
pour sous Android OS 5.0, j'obtiens cette erreurjava.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams
silverFoxA
ViewGroup.LayoutParams params = gridView.getLayoutParams (); lance une NullPointerException
Luke Allison
4

Les tacones trouvés répondent utiles ... alors je l'ai porté en 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
la source
1
Bravo mec. Fonctionne très bien dans xamarin.android
Suchith
0

Calculez simplement la hauteur pour AT_MOST et réglez sur mesure. Ici, GridView Scroll ne fonctionnera pas ainsi. Besoin d'utiliser explicitement la vue de défilement vertical.

 @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
la source
Cette méthode vous aide-t-elle à faire défiler GridView
Suchith