How to add elements to a GridLayout dynamically with different column widths for every row based on element size? [duplicate]

前提是你 提交于 2019-12-07 22:27:45

问题


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?


回答1:


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;


来源:https://stackoverflow.com/questions/35361905/how-to-add-elements-to-a-gridlayout-dynamically-with-different-column-widths-for

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!