This question already has an answer here:
-
Android GridLayout with dynamic number of columns per row
2 answers
I have a variable-size array
of tags that I want to show inside a gridlayout
. The problem is that the tags vary in length and it looks kind of messy to put them inside a statically
defined grid even when some tags are much bigger than others.
So I would like to be able to put tag after tag until there is no more space left for a full tag and then go to the next row. Basically something like this:
| *** ****** ****** ** ***** |
| ** ***** *** ********* *** |
| ********* ***** *** |
| ************** ******** |
| ****** ******** ******** |
| ***************** |
| ************** ***** ***** |
I think you guys get the point.
Right now, I got something like this but its not quite doing what I need.
int total = tags.size();
int column = 3;
int row = total / column;
suggestedTagsLayout.setColumnCount(column);
suggestedTagsLayout.setRowCount(row + 1);
for (int i = 0, c = 0, r = 0; i < total; i++, c++) {
if (c == column) {
c = 0;
r++;
}
TextView tag = createNewTag(tags.get(i));
tag.setBackgroundColor(Color.BLUE);
tag.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
GridLayout.Spec rowSpan = GridLayout.spec(GridLayout.UNDEFINED, 1);
GridLayout.Spec colspan = GridLayout.spec(GridLayout.UNDEFINED, 1);
if (r == 0 && c == 0) {
logger.e("spec");
colspan = GridLayout.spec(GridLayout.UNDEFINED, 1);
rowSpan = GridLayout.spec(GridLayout.UNDEFINED, 1);
}
logger.d("\n\ntag = " + tag.getText().toString());
int width = tag.getWidth();
int height = tag.getHeight();
logger.d("width = " + width);
logger.d("height = " + height);
width = tag.getMeasuredWidth();
height = tag.getMeasuredHeight();
logger.d("getMeasuredWidth = " + width);
logger.d("getMeasuredHeight = " + height);
GridLayout.LayoutParams gridParam = new GridLayout.LayoutParams(
rowSpan, colspan);
suggestedTagsLayout.addView(tag, gridParam);
}
This looks more like :
| ***** **** ******** **** |
| **** ******** |
| ******* ****** |
So I am also trying to get the width of each TextView
so that I can calculate the spaces manually and add items accordingly but this is also failing as the dimensions are still 0
because they are not drawn. So it seems I will have to use the API accordingly to get the desired behaviour.
I am still new to this GridLayout
and the api is quite large so could you guys help me out?
Allright,, I managed to solve my own problem by calculating how much space is needed and how much space is left. When there is too little space left for the tag to be inserted, it will go to the next row.
private void fillSuggestedTagsLayout() {
// get all strings to insert in tag
ArrayList<String> tagsText = getTagsList();
// maps for connecting string to textview and string to textview width
HashMap<String, TextView> tagMap = new HashMap<>();
HashMap<String, Integer> tagWidthMap = new HashMap<>();
// total width
float totalWidth = 0;
// for each string
for (String s : tagsText) {
// create textview
TextView txtView = createNewTag(s, false);
// store textview with string
tagMap.put(s, txtView);
// store width also
tagWidthMap.put(s, txtView.getMeasuredWidth());
logger.d("width of txtView = " + txtView.getMeasuredWidth());
// count all textview widths in order to calculate amount of rows needed for display
totalWidth += txtView.getMeasuredWidth();
}
// gridlayout width to calculate rows needed
final float layoutWidth = suggestedTagsLayout.getWidth();
logger.e("gridlayout width = " + layoutWidth);
logger.e("total = " + totalWidth);
// amount of rows equals to totalwidth of elements / layout width
final float rows = totalWidth / layoutWidth;
int rowsRounded = (int) rows;
// rows needed could be 1,2 or something meaning that we need extra space.
// every decimal will need to get rounded up. 1.2 becomes 2 for example
if (rows > rowsRounded) {
rowsRounded++;
}
// total amount of elements
int total = tagsText.size();
// column count, 200 in order to have great precision in position of elements
final int columns = 200;
// amount of space needed per column
final float dpPerColumn = layoutWidth / (float) columns;
// set layout specs
suggestedTagsLayout.setColumnCount(columns);
suggestedTagsLayout.setRowCount(rowsRounded);
for (int item = 0, column = 0, row = 0; item < total; item++) {
// get string
String s = tagsText.get(item);
// get txtview
TextView tag = tagMap.get(s);
tag.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
// calculate amount of columns needed for tag.
// tagwidth/sizePerColumn
float colsToSpan = tagWidthMap.get(s) / dpPerColumn;
// again, round up above in order to accomodate space needed
int colsToSpanRounded = (int) colsToSpan;
if (colsToSpan < colsToSpanRounded) {
colsToSpanRounded++;
}
// now that we know the amount space needed for tag,
// check if there is enough space on this row
if ((column + colsToSpanRounded) > columns) {
column = 0;
row++;
}
// put tag on row N, span 1 row only
GridLayout.Spec rowSpan = GridLayout.spec(row, 1);
// put tag on column N, span N rows
GridLayout.Spec colSpan = GridLayout.spec(column, colsToSpanRounded);
logger.d("tag: " + s + " is taking " + colsToSpanRounded + " columns");
logger.d("c = " + column + " colsToSpan =" + colsToSpanRounded);
logger.d("spanning between " + column + " and " + (column + colsToSpanRounded));
logger.d(" ");
// increment column
column += colsToSpanRounded;
GridLayout.LayoutParams gridParam = new GridLayout.LayoutParams(
rowSpan, colSpan);
// add tag
suggestedTagsLayout.addView(tag, gridParam);
}
}
The tag is created and meassured with the following:
private TextView createNewTag(final String tagText, boolean withImage) {
TextView textView = new TextView(getActivity());
textView.setPadding(8,8,8,8);
textView.setTypeface(Typeface.DEFAULT);
textView.setText(tagText, TextView.BufferType.SPANNABLE);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
textView.setBackground(getActivity().getResources().getDrawable(R.drawable.tag_background));
if(withImage) {
Drawable img = getActivity().getResources().getDrawable(R.drawable.delete_tag_icon);
textView.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null);
}
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
textView.measure(widthMeasureSpec, heightMeasureSpec);
logger.d(tagText);
return textView;
}
deviceWith is calculated by doing:
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
deviceWidth = metrics.widthPixels;
deviceHeight = metrics.heightPixels;