Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making GridView items square

I would like the items of my GridView to be square. There are 2 columns and the items width is fill_parent (e.g. they take as much horizontal space as possible. The items are custom views.

How do I make the items height to be equal to their variable width?

like image 340
anagaf Avatar asked Jul 02 '11 14:07

anagaf


4 Answers

There is a simpler solution when GridView columns are stretched. Just override the onMeasure of the GridView item layout with...

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
like image 62
jdamcd Avatar answered Sep 23 '22 21:09

jdamcd


Or if you want to extend a View just do something really simple like:

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

It's worth noting that super.onMeasure() is not needed. onMeasured requirement is that you must call setMeasuredDimension.

like image 56
Chris.Jenkins Avatar answered Sep 21 '22 21:09

Chris.Jenkins


I'm not sure this is possible with the current widgets. Your best bet might be to put your custom view in a custom "SquareView". This view could just contain 1 child view, and force the height to equal the width when its onLayout method is called.

I never tried to do something like that, but I think it shouldn't be too difficult. An alternative (and maybe slightly easier) solution might be to subclass your custom view's root layout (like, if it's a LinearLayout, make a SquareLinearLayout), and use that as a container instead.

edit : Here's a basic implementation which seems to work for me :

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

It's designed to have a unique child, but I ignored all of the checks for the sake of simplicity. The basic idea is to measure the child with the width/height parameters set by the GridView (in my case, it uses numColumns=4 to calculate the width), and then do a second pass with the final dimensions, with height=width... The layout is just a plain layout, which layouts the unique child at (0, 0) with the desired dimensions (right-left, down-up).

And here's the XML used for the GridView items :

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

I used a LinearLayout inside the SquareView in order to have it manage all the gravity possibilities, margins, etc.

I'm not sure how well (or bad) this widget would react to orientation and dimension changes, but it seems to work correctly.

like image 16
Gregory Avatar answered Sep 20 '22 21:09

Gregory


It ends up being fairly easy to get the grid item square.

In your "GetView" method of your grid adapter, just do:

@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;
}
like image 13
SteveBorkman Avatar answered Sep 21 '22 21:09

SteveBorkman