web-dev-qa-db-fra.com

Rendre les éléments GridView carrés

Je voudrais que les éléments de mon GridView soient carrés. Il y a 2 colonnes et la largeur des éléments est fill_parent _ (par exemple, ils prennent le plus grand espace horizontal possible. Les éléments sont des vues personnalisées.

Comment faire en sorte que la hauteur des éléments soit égale à leur largeur variable?

77
anagaf

Il existe une solution plus simple lorsque les colonnes GridView sont étirées. Remplacez simplement la disposition de l'élément onMeasure de GridView par ...

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
107
jdamcd

Ou si vous voulez étendre une vue, faites quelque chose de vraiment simple comme:

public class SquareImageView extends ImageView
{

    public SquareImageView(final Context context)
    {
        super(context);
    }

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

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


    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
    {
        final int width = getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec);
        setMeasuredDimension(width, width);
    }

    @Override
    protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh)
    {
        super.onSizeChanged(w, w, oldw, oldh);
    }
}

Il est à noter que super.onMeasure() n'est pas nécessaire. onMeasured l'exigence est que vous devez appeler setMeasuredDimension.

53
Chris.Jenkins

Je ne suis pas sûr que cela soit possible avec les widgets actuels. Votre meilleur choix pourrait être de placer votre vue personnalisée dans un "SquareView" personnalisé. Cette vue ne peut contenir qu'une vue enfant et forcer la hauteur à la largeur lorsque sa méthode onLayout est appelée.

Je n'ai jamais essayé de faire quelque chose comme ça, mais je pense que cela ne devrait pas être trop difficile. Une solution alternative (et peut-être légèrement plus simple) pourrait consister à sous-classer la disposition racine de votre vue personnalisée (par exemple, s'il s'agit d'un LinearLayout, créez un SquareLinearLayout) et à l'utiliser à la place comme conteneur.

edit: Voici une implémentation de base qui semble fonctionner pour moi:

package com.mantano.widget;

import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.View;
import Android.view.ViewGroup;

public class SquareView extends ViewGroup {

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

    @Override
    protected void onLayout(boolean changed, int l, int u, int r, int d) {
        getChildAt(0).layout(0, 0, r-l, d-u); // Layout with max size
    }

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

        View child = getChildAt(0);
        child.measure(widthMeasureSpec, widthMeasureSpec);
        int width = resolveSize(child.getMeasuredWidth(), widthMeasureSpec);
        child.measure(width, width); // 2nd pass with the correct size
        setMeasuredDimension(width, width);
    }
}

Il est conçu pour avoir un enfant unique, mais j'ai ignoré toutes les vérifications dans un souci de simplicité. L'idée de base est de mesurer l'enfant avec les paramètres largeur/hauteur définis par le GridView (dans mon cas, il utilise numColumns = 4 pour calculer la largeur), puis d'effectuer un deuxième passage avec les dimensions finales, avec height = width. .. La mise en page est simplement une mise en page simple, qui met en page l'enfant unique en (0, 0) avec les dimensions souhaitées (droite-gauche, en bas).

Et voici le XML utilisé pour les éléments GridView:

<?xml version="1.0" encoding="utf-8"?>
<com.mantano.widget.SquareView
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent" Android:layout_height="wrap_content">

    <LinearLayout Android:id="@+id/item" Android:layout_width="fill_parent"
        Android:layout_height="fill_parent" Android:orientation="horizontal"
        Android:gravity="center">

        <TextView Android:id="@+id/text" Android:layout_width="fill_parent"
            Android:layout_height="wrap_content" Android:text="Hello world" />
    </LinearLayout>
</com.mantano.widget.SquareView>

J'ai utilisé LinearLayout à l'intérieur de SquareView afin de lui permettre de gérer toutes les possibilités de gravité, les marges, etc.

Je ne sais pas si ce widget réagira bien (ou mal) aux changements d'orientation et de dimension, mais il semble fonctionner correctement.

15
Gregory

En fin de compte, il est assez facile d’obtenir le carré de l’élément de grille.

Dans votre méthode "GetView" de votre adaptateur de grille, faites simplement:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    GridView grid = (GridView)parent;
    int size = grid.getRequestedColumnWidth();

    TextView text = new TextView(getContext());
    text.setLayoutParams(new GridView.LayoutParams(size, size));

    // Whatever else you need to set on your view

    return text;
}
12
SteveBorkman

Je ne sais pas si c'est la meilleure façon, mais j'y parviens en faisant en sorte que ma vue personnalisée écrase onSizeChanged de cette façon:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    if (getLayoutParams() != null && w != h) {
        getLayoutParams().height = w;
        setLayoutParams(getLayoutParams());
    }
}

J'utilise cette vue personnalisée à l'intérieur d'un LinearLayout et d'un GridView et dans les deux cas, elle affiche un carré!

6
Luckcheese

Cela a fonctionné pour moi!

Si vous êtes comme moi et que vous ne pouvez pas utiliser getRequestedColumnWidth () car votre minSdk est inférieur à 16, je suggère cette option.

  1. dans votre fragment:

    DisplayMetrics dm = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); int size = dm.widthPixels / nbColumns; CustomAdapter adapter = new CustomAdapter(list, size, getActivity());

  2. dans votre adaptateur (dans getView (position int, View convertView, ViewGroup parent))

    v.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, size));

  3. fragment.xml:

    <GridView Android:id="@+id/gridView" Android:layout_width="match_parent" Android:layout_height="match_parent" Android:horizontalSpacing="3dp" Android:verticalSpacing="3dp" Android:numColumns="4" Android:stretchMode="columnWidth" />

  4. custom_item.xml: (par exemple)

    <ImageView xmlns:Android="http://schemas.Android.com/apk/res/Android" Android:id="@+id/picture" Android:layout_width="match_parent" Android:layout_height="match_parent" Android:scaleType="centerCrop" />

J'espère que ça va aider quelqu'un!

6
Anne-Claire

si vous définissez un nombre statique de colonnes dans le fichier XML, vous pouvez alors prendre la largeur de la vue et la diviser par le nombre de colonnes.

si vous utilisez auto_fit, il sera un peu difficile d'obtenir le nombre de colonnes (il n'y a pas de méthode getColumnCount ()), btw this question devrait vous aider d'une manière ou d'une autre.

c'est le code que j'utilise dans la méthode getView(...) de l'adaptateur avec un nombre fixe de colonnes:

    item_side = mFragment.holder.grid.getWidth() / N_COL;
    v.getLayoutParams().height = item_side;
    v.getLayoutParams().width = item_side;
5
Mario Lenci

Voici ce que je fais pour afficher des cellules carrées dans un GridView. Je ne sais pas si vous voulez des cellules carrées ou autre chose.

GridView grid = new GridView( this );
grid.setColumnWidth( UIScheme.cellSize );
grid.setVerticalSpacing( UIScheme.gap );
grid.setStretchMode( GridView.STRETCH_COLUMN_WIDTH );
grid.setNumColumns( GridView.AUTO_FIT );

Et puis la vue que je crée pour chaque cellule, je dois lui faire ce qui suit:

cell.setLayoutParams( new GridView.LayoutParams(iconSize, iconSize) );
4
Sileria

Essayer

<GridView
...
Android:stretchMode="columnWidth" />

Vous pouvez également jouer avec d'autres modes

4
Art

Basé sur réponse de SteveBorkman , qui correspond à l'API 16+:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    GridView grid = (GridView)parent;
    int size = grid.getColumnWidth();

    if (convertView == null){
        convertView = LayoutInflater.from(context).inflate(R.layout.your_item, null);
        convertView.setLayoutParams(new GridView.LayoutParams(size, size));
    }

     //Modify your convertView here

     return convertView;
}
3
Joaquin Iurchuk

Dans le sens de la réponse de @ Gregory, je devais envelopper mon image dans un LinearLayout afin d'empêcher GridView de manipuler ses dimensions à partir d'un carré. Notez que LinearLayout externe doit être défini pour avoir la dimension de l'image et que la largeur de la colonne GridView doit correspondre à la largeur de l'image PLUS toute marge. Par exemple:

    <!-- LinearLayout wrapper necessary to wrap image button in order to keep square;
    otherwise, the grid view distorts it into rectangle.

    also, margin top and right allows the indicator overlay to extend top and right.

    NB: grid width is set in filter_icon_page.xml, and must correspond to size + margin
    -->
<LinearLayout
        Android:id="@+id/sport_icon_lay"
        Android:layout_width="60dp"
        Android:layout_height="60dp"
        Android:orientation="vertical"

        Android:layout_marginRight="6dp"
        Android:layout_marginTop="6dp"
        >

    <ImageButton
            Android:id="@+id/sport_icon"
            Android:layout_width="60dp"
            Android:layout_height="60dp"
            Android:maxHeight="60dp"
            Android:maxWidth="60dp"
            Android:scaleType="fitCenter"
            />
</LinearLayout>

et le GridView comme:

   <GridView
        Android:id="@+id/grid"
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent"
        Android:fillViewport="true"

        Android:columnWidth="66dp"

        Android:numColumns="auto_fit"
        Android:verticalSpacing="25dp"
        Android:horizontalSpacing="24dp"
        Android:stretchMode="spacingWidth"

        />
1
larham1