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
]2
It doesn't work as per my need. Please help . Thanks in advance.
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++;
}
}
}
}
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With