0

I have a GridView that I have filled with 64 60x60px png's. I want the GridView to display them all as close to a perfect square as I can so I have set the numColumns in the XML to 8 so now I have an 8x8 gird.

Here is what it looks like:

enter image description here

My images actually have a small border at the very edge though that is being cropped off. Here I drew on the top left image what they should look like when displayed:

enter image description here

Here is my XML:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/textFieldFU"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <GridView
    android:id="@+id/gridview"
    android:layout_width="fill_parent" 
    android:layout_height="600dp"
    android:numColumns="8"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="0dp"
    android:stretchMode="columnWidth"
    android:gravity="center"
/>

</RelativeLayout>

When I was using 40x40px and 50x50px size png's they worked fine, but they were too small to easily see my little symbols. I have changed everything in the XML that I could think of but no matter how much spacing I give or where I give it, the images stay cropped even when there is ample room.

How can I make the GridView display the full, un-cropped images?

For the love of all that is holy, I'm really dumb. I had forgotten that in my "ImageAdapter" class I had set had used the ImageView setLayoutParams method and set them to (50, 50). Sorry for wasting you good peoples time.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView iv;
    if (convertView != null) {
        iv = (ImageView) convertView;
    } else {
        iv = new ImageView(context);
        ******iv.setLayoutParams(new GridView.LayoutParams(50, 50));******
        iv.setScaleType(ScaleType.CENTER);
        iv.setPadding(0, 0, 0, 0);
    }
    iv.setImageResource(images[position]);
    return iv;
}
ChrisWilson4
  • 195
  • 4
  • 23
  • Have you tried to set ScaleType for the ImageView in GridItem as android:scaleType="fitCenter". – SKK Apr 25 '13 at 11:09
  • I am not sure about this but perhaps your problem occurs because you have a fixed number of columns defined. Your grid doesn't have space to show all 8 columns in total so it crops them. Could you try: 'auto_fit' instead of '8' at numColumns? – Bram Apr 25 '13 at 11:13
  • @Bram I will try just to see if it eliminates the cropping, but I cannot do that since I must maintain a grid. – ChrisWilson4 Apr 25 '13 at 11:20
  • @Bram It still freaking crops them, even though there is just a ton of empty space surrounding them. – ChrisWilson4 Apr 25 '13 at 11:22
  • @Santhosh android:scaleType is not an available modifier, only scaleX, and scaleY. – ChrisWilson4 Apr 25 '13 at 11:24
  • ScaleType should be an option on the ImageViews, what API Level are you targeting? – Leon Lucardie Apr 25 '13 at 11:32
  • @ScaleType I have the minSDKVersion="14" and the targetSdkVersion="17". Not sure if that answers your question. – ChrisWilson4 Apr 25 '13 at 11:35
  • have you considered using a custom flowlayout? https://github.com/ApmeM/android-flowlayout – string.Empty Apr 25 '13 at 11:42
  • @NicolasTyler No, I have not been introduced to that idea yet, It seems intimidating to try, but I will do it now and try not to break anything. – ChrisWilson4 Apr 25 '13 at 11:48
  • @NicolasTyler I broke it. I added the code from the link to my XML, but I get erros saying "No resource identifier found for attribute ...." every time I use the "f:attributeName="example"" instead of "android:attributeName:"example"". – ChrisWilson4 Apr 25 '13 at 11:58
  • @NicolasTyler Sorry, I've never used GitHub, it seems like I'm suppose to download one of those files at the top, but I can't figure it out. – ChrisWilson4 Apr 25 '13 at 12:02
  • @LeonLucardie and Santhosh, You two were right about scaleType. setScaleType is available through my ImageAdapter class as a method, as I used it above, in the edited post. I had tried inserting it into my XML inside the GridView. – ChrisWilson4 Apr 25 '13 at 12:15
  • ill make an answer to explain how to use the flowlayout. – string.Empty Apr 25 '13 at 12:27

1 Answers1

0

To use flowlayout make a java class called FlowLayout to be a custom control in android.

.../src/FlowLayout.java:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class FlowLayout extends ViewGroup
{
    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;

    private int horizontalSpacing = 20;
    private int verticalSpacing = 20;
    private int orientation = 0;

    private int innerPadding = 12;

    public FlowLayout(Context context)
    {
        super(context);
    }

    public FlowLayout(Context context, AttributeSet attributeSet)
    {
        super(context, attributeSet);
    }

    public FlowLayout(Context context, AttributeSet attributeSet, int defStyle)
    {
        super(context, attributeSet, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft()+innerPadding;

        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        int size;
        int mode;

        if (orientation == HORIZONTAL)
        {
            size = sizeWidth;
            mode = modeWidth;
        }
        else
        {
            size = sizeHeight;
            mode = modeHeight;
        }

        int lineThicknessWithSpacing = 0;
        int lineThickness = 0;
        int lineLengthWithSpacing = 0;
        int lineLength;

        int prevLinePosition = 0;

        int controlMaxLength = 0;
        int controlMaxThickness = 0;

        final int count = getChildCount();
        for (int i = 0; i < count; i++)
        {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;

            child.measure
            (
                MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeWidth),
                MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeHeight)
            );

            LayoutParams lp = (LayoutParams) child.getLayoutParams();

            int hSpacing = this.getHorizontalSpacing(lp);
            int vSpacing = this.getVerticalSpacing(lp);

            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            int childLength;
            int childThickness;
            int spacingLength;
            int spacingThickness;

            if (orientation == HORIZONTAL)
            {
                childLength = childWidth;
                childThickness = childHeight;
                spacingLength = hSpacing;
                spacingThickness = vSpacing;
            }
            else
            {
                childLength = childHeight;
                childThickness = childWidth;
                spacingLength = vSpacing;
                spacingThickness = hSpacing;
            }

            lineLength = lineLengthWithSpacing + childLength;
            lineLengthWithSpacing = lineLength + spacingLength;

            boolean newLine = lp.newLine || (mode != MeasureSpec.UNSPECIFIED && lineLength > size);
            if (newLine)
            {
                prevLinePosition = prevLinePosition + lineThicknessWithSpacing;

                lineThickness = childThickness;
                lineLength = childLength;
                lineThicknessWithSpacing = childThickness + spacingThickness;
                lineLengthWithSpacing = lineLength + spacingLength;
            }

            lineThicknessWithSpacing = Math.max(lineThicknessWithSpacing, childThickness + spacingThickness);
            lineThickness = Math.max(lineThickness, childThickness);

            int posX;
            int posY;
            if (orientation == HORIZONTAL)
            {
                posX = innerPadding + getPaddingLeft() + lineLength - childLength;
                posY = getPaddingTop() + prevLinePosition;
            }
            else
            {
                posX = getPaddingLeft() + prevLinePosition;
                posY = innerPadding + getPaddingTop() + lineLength - childHeight;
            }
            lp.setPosition(posX, posY);

            controlMaxLength = Math.max(controlMaxLength, lineLength);
            controlMaxThickness = prevLinePosition + lineThickness;
        }

        if (orientation == HORIZONTAL)
            this.setMeasuredDimension(resolveSize(controlMaxLength, widthMeasureSpec), resolveSize(controlMaxThickness, heightMeasureSpec));
        else
            this.setMeasuredDimension(resolveSize(controlMaxThickness, widthMeasureSpec), resolveSize(controlMaxLength, heightMeasureSpec));
    }

    private int getVerticalSpacing(LayoutParams lp)
    {
        int vSpacing;
        if (lp.verticalSpacingSpecified())
            vSpacing = lp.verticalSpacing;
        else
            vSpacing = this.verticalSpacing;
        return vSpacing;
    }

    private int getHorizontalSpacing(LayoutParams lp)
    {
        int hSpacing;
        if (lp.horizontalSpacingSpecified())
            hSpacing = lp.horizontalSpacing;
        else
            hSpacing = this.horizontalSpacing;
        return hSpacing;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        final int count = getChildCount();
        for (int i = 0; i < count; i++)
        {
            View child = getChildAt(i);
            LayoutParams lp = (LayoutParams) child.getLayoutParams();
            child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
        }
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime)
    {
        return super.drawChild(canvas, child, drawingTime);
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p)
    {
        return p instanceof LayoutParams;
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams()
    {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attributeSet)
    {
        return new LayoutParams(getContext(), attributeSet);
    }

    @Override
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p)
    {
        return new LayoutParams(p);
    }

    public static class LayoutParams extends ViewGroup.LayoutParams
    {
        private static int NO_SPACING = -1;

        private int x;
        private int y;
        private int horizontalSpacing = NO_SPACING;
        private int verticalSpacing = NO_SPACING;
        private boolean newLine = false;

        public LayoutParams(Context context, AttributeSet attributeSet)
        {
            super(context, attributeSet);
            this.readStyleParameters(context, attributeSet);
        }

        public LayoutParams(int width, int height)
        {
            super(width, height);
        }

        public LayoutParams(ViewGroup.LayoutParams layoutParams)
        {
            super(layoutParams);
        }

        public boolean horizontalSpacingSpecified()
        {
            return horizontalSpacing != NO_SPACING;
        }

        public boolean verticalSpacingSpecified()
        {
            return verticalSpacing != NO_SPACING;
        }

        public void setPosition(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        private void readStyleParameters(Context context, AttributeSet attributeSet)
        {
            TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams);
            try
            {
                horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, NO_SPACING);
                verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_verticalSpacing, NO_SPACING);
                newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false);
            }
            finally
            {
                a.recycle();
            }
        }
    }
}

Then you create custom attributes for your views that are going to be inside the flow layout view.

.../res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FlowLayout_LayoutParams">
        <attr name="layout_newLine" format="boolean"/>
        <attr name="layout_horizontalSpacing" format="dimension"/>
        <attr name="layout_verticalSpacing" format="dimension"/>
    </declare-styleable>
</resources>

Then in the xml layout you just add:

<[PATH_TO_CLASS].FlowLayout
    xmlns:flowLayout="http://schemas.android.com/apk/res/za.co.lawdata.searchworks"
    android:id="@+id/flow_layout"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        flowLayout:layout_verticalSpacing="50dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        flowLayout:layout_newLine="true"
        flowLayout:layout_horizontalSpacing="50dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"/>

</[PATH_TO_CLASS].FlowLayout>

And replace [PATH_TO_CLASS] with your package path eg: com.example.appname

flowLayout:layout_verticalSpacing="50dp" will set the vertical space between the item. The default is set in the java class.

flowLayout:layout_horizontalSpacing="50dp" will set the horizontal space between the item. The default is set in the java class.

flowLayout:layout_newLine="true" will put the item on a new line.

This is an edit from this git: https://github.com/ApmeM/android-flowlayout

string.Empty
  • 10,393
  • 4
  • 39
  • 67