15

I have created a grid containing full of texts. I want the text to auto-fit according to screen size. I have tried the following code,

    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
    int noOfColumns = (int) (dpWidth / 50);
    return noOfColumns;

I want output something like this

image]2

imag2 It doesn't work as per my need. Please help . Thanks in advance.

Anusha
  • 939
  • 3
  • 13
  • 31

7 Answers7

6

Here's a custom implementation of GridLayout that will do what you need: AutoGridLayout

public class AutoGridLayout extends GridLayout {

    private int defaultColumnCount;
    private int columnWidth;

    public AutoGridLayout(Context context) {
        super(context);
        init(null, 0);
    }

    public AutoGridLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public AutoGridLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs, defStyleAttr);
    }

    private void init(AttributeSet attrs, int defStyleAttr) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.AutoGridLayout, 0, defStyleAttr);
        try {
            columnWidth = a.getDimensionPixelSize(R.styleable.AutoGridLayout_columnWidth, 0);

            int[] set = { android.R.attr.columnCount /* id 0 */ };
            a = getContext().obtainStyledAttributes(attrs, set, 0, defStyleAttr);
            defaultColumnCount = a.getInt(0, 10);
        } finally {
            a.recycle();
        }

        /* Initially set columnCount to 1, will be changed automatically later. */
        setColumnCount(1);
    }

    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        super.onMeasure(widthSpec, heightSpec);

        int width = MeasureSpec.getSize(widthSpec);
        if (columnWidth > 0 && width > 0) {
            int totalSpace = width - getPaddingRight() - getPaddingLeft();
            int columnCount = Math.max(1, totalSpace / columnWidth);
            setColumnCount(columnCount);
        } else {
            setColumnCount(defaultColumnCount);
        }
    }
}

Just add to your XML layout file like this:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.km.myproject.customview.AutoGridLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnCount="5"
        app:columnWidth="50dp"/>

</FrameLayout>

Using columnWidth will try to calculate how many columns can fit and set the optimal span count automatically. If not used (or failed to measure for some reason), the columnCount attribute will be used.

Hope this helps!

km.
  • 151
  • 2
  • 3
4

Use FlexboxLayout with RecyclerView to handle this type of layout

RecyclerView recyclerView = (RecyclerView) context.findViewById(R.id.recyclerview);
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(context);
layoutManager.setFlexDirection(FlexDirection.COLUMN);
layoutManager.setJustifyContent(JustifyContent.FLEX_START);
recyclerView.setLayoutManager(layoutManager);

For more check FlexboxLayout,

FlexboxLayout also handle different width height of view just like images in Gallery

Krishna Sony
  • 1,286
  • 13
  • 27
2

Here is an implementation of a grid layout that does all the calculations for you. It places all child views in an equally spaced grid with equal margins. It also optimizes the numbers of columns so that not to have all rows as full as possible (for example, 9 child views would fit on 3 rows as 4,4,1, but 3,3,3 looks much better) It's all dynamic, so don't worry about landscape/portrait/phone/tablet/TV


package .......;

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

/* A labor-saving layout
/  dynamically places all children on an equally-spaced grid.
   All children get the width/height of the largest child - so they all look similar
 */
public class AutoGridLayout extends ViewGroup
{

    private int mMaxHeight;
    private int mMaxWidth;

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

    public AutoGridLayout(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

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

    @Override
    public boolean shouldDelayChildPressedState()
    {
        return false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int count = getChildCount();

        mMaxHeight = 0;
        mMaxWidth = 0;
        int childState = 0;

        for (int i = 0; i < count; i++)
        {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE)
            {
                measureChild(child, widthMeasureSpec,  heightMeasureSpec);

                mMaxWidth = Math.max(mMaxWidth, child.getMeasuredWidth());
                mMaxHeight = Math.max(mMaxHeight, child.getMeasuredHeight());
            }
        }

        mMaxHeight = Math.max(mMaxHeight, getSuggestedMinimumHeight());
        mMaxWidth = Math.max(mMaxWidth, getSuggestedMinimumWidth());

        setMeasuredDimension(resolveSizeAndState(mMaxWidth, widthMeasureSpec, childState),
                             resolveSizeAndState(mMaxHeight, heightMeasureSpec,
                                                 childState << MEASURED_HEIGHT_STATE_SHIFT));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        final float pxWidth = (right - left + 1);
        final float pxHeight  = (1 + bottom - top);
        final int totalChildCount = getChildCount();
        int count = 0;
        for (int i = 0; i < totalChildCount; i++)
        {
            if (getChildAt(i).getVisibility() != GONE)
                count++;
        }

        final float minSpacing = pxWidth / 20;
        final int maxPossibleColumns = (int) (pxWidth / (mMaxWidth + minSpacing));
        final int rows = (int)Math.ceil((float)count / maxPossibleColumns);
        final int voidsAtLastRow = (rows * maxPossibleColumns - count);
        // distribute the voids to get an even distribution is possible
        final int nColumns = maxPossibleColumns - voidsAtLastRow / rows;

        // equal spaces as margins and between childs (#spaces = #child + 1)
        final int xSpace = (int)Math.max(0,(pxWidth - nColumns * mMaxWidth) / (nColumns + 1));
        final int ySpace = (int)Math.max(0,(pxHeight - rows * mMaxHeight) / (rows + 1));

        int n = 0;
        for (int i = 0; i < totalChildCount; i++)
        {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE)
            {
                final int col = n % nColumns;
                final int x = xSpace + (xSpace + mMaxWidth) * col;

                final int row = n / nColumns;
                final int y = ySpace + (ySpace + mMaxHeight) * row;

                // Place the child.
                child.layout(x, y,x+mMaxWidth,y+mMaxHeight);
                n++;
            }
        }
    }

}

Sample

Erez Amir
  • 131
  • 1
  • 6
0

Do the following;

  • Use your code to calculate column count in onCreate or onCreateView. Keep in mind spacing between columns.

  • Call setColumnCount on the GridLayout with above count

  • In your xml, add the attribute android:layout_columnWeight="1" to all items in GridLayout. This will cause the columns to stretch in API 21 and above.

  • In pre API 21, you can either horizontal center the GridView itself, so that it looks decent. Or better yet, calculate preferred columnWidth (gridWidth / columnCount), and iterate through all items in grid (ViewGroup), and set their width to columnWidth.

lionscribe
  • 3,413
  • 1
  • 16
  • 21
0

It would be difficult to make GridLayout do what you need:

  • Even though you can read the screen width from a DisplayMetrics, that method would be incompatible with new versions of Android that support split-screen. You need the width of the parent view, not the whole screen.

  • Even assuming that display metrics gives you a reliable width for the window displaying your activity, this logic will break as soon as you put the layout in a fragment next to another fragment. It doesn't make sense to create something so inflexible.

  • The width of the parent view is not known until layout is complete. That doesn't make it impossible to use, just tricky.

The simple thing to do instead is use a GridView which is better designed for this purpose because it has the autofit option for number of columns.

x-code
  • 2,940
  • 1
  • 18
  • 19
  • Actually it seems that `getMetrics` returns the virtual size of the split window, so it will work well. You would use `getRealMetrics` to get size of full screen. – lionscribe Sep 12 '16 at 02:27
  • Thanks for that and I'll take your word for it. I would still worry about RemixOS, various schemes Samsung and other hardware companies use in skins, and in general what might happen on some device I did not test with. – x-code Sep 12 '16 at 03:20
  • Actually I never tested it myself, I was just quoting from what I read at http://stackoverflow.com/questions/36706365/how-to-get-actual-screen-size-after-android-n – lionscribe Sep 12 '16 at 03:58
  • Actually I want drag and drop functionality inside the grid .I have tried using auto-fit for Grid view but I was getting an error. Please check my question here http://stackoverflow.com/questions/39434558/java-lang-unsupportedoperationexception-addviewview-int-is-not-supported-in So I tried the same using Grid Layout @lionscribe – Anusha Sep 12 '16 at 04:07
  • I have tried grid view but was getting some other error. Please have a look at my error here http://stackoverflow.com/questions/39434558/java-lang-unsupportedoperationexception-addviewview-int-is-not-supported-in @x-code – Anusha Sep 12 '16 at 04:09
  • Based on your other question you need to support drag and drop. That being the case you are right that grid view is not a good choice. I don't have an easy answer than, sorry. – x-code Sep 12 '16 at 13:56
0

You can use dimens.xml file for this. Then update android:columnCount="@dimen/columnCount" in GridLayout

https://suragch.medium.com/using-dimens-xml-in-android-10dec2fe485c

Dumindu De Silva
  • 153
  • 1
  • 11
-1

For gridlayout

 <?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:columnCount="4"
    android:orientation="horizontal" >
    <Button android:text="1" />
    <Button android:text="2" />
    <Button android:text="3" />
    <Button android:text="4" />
    <Button android:text="5" />
    <Button android:text="6" />
    <Button android:text="7" />
    <Button android:text="8" />
    <Button android:text="9" />
    <Button android:text="10" />
    <Button android:text="11" />
    <Button android:text="12" />
    <Button android:text="13" />
    <Button android:text="14" />
    <Button android:text="15" />
    <Button android:text="16" />
</GridLayout>

programmatically:

GridLayout gridLayout = new GridLayout(this);
gridLayout .setColumnCount(4);
///...

an example: https://stackoverflow.com/a/14715333/1979882

to adjust gridview use this method:

private void adjustGridView() {
  gv.setNumColumns(GridView.AUTO_FIT);
  gv.setColumnWidth(70);
}
Community
  • 1
  • 1
Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
  • Can we implement the same in Grid layout ? Because I don't find auto_fit function in grid layout @Vyacheslav – Anusha Sep 11 '16 at 14:58
  • 1
    I want column to be auto_fit and not hard code value @Vyacheslav – Anusha Sep 11 '16 at 15:43
  • Updated code way. Please, describe the problem more precisely. With code. @Anusha – Vyacheslav Sep 11 '16 at 16:11
  • I don't want to specify the columCount like you are specifying but I want to be as auto_fit . How to set as Auto_fit in gridlayout? @Vyacheslav – Anusha Sep 11 '16 at 16:13
  • How ? They are autofitted in grid view . But how about grid layout ? and have referred all those links but nothing helped@Vyacheslav – Anusha Sep 11 '16 at 16:15
  • Look at the url I gave – Vyacheslav Sep 11 '16 at 16:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/123115/discussion-between-anusha-and-vyacheslav). – Anusha Sep 11 '16 at 16:17