【问题标题】:How to add elements to a GridLayout dynamically with different column widths for every row based on element size? [duplicate]如何根据元素大小为每行动态添加不同列宽的元素到 GridLayout? [复制]
【发布时间】:2016-02-12 11:50:27
【问题描述】:

我有一个可变大小的标签array,我想在gridlayout 中显示这些标签。问题是标签的长度各不相同,即使有些标签比其他标签大得多,将它们放在statically 定义的网格中看起来也有点乱。

所以我希望能够将标签一个接一个地放置,直到没有更多空间留给一个完整的标签,然后转到下一行。基本上是这样的:

| *** ****** ****** ** ***** |
| ** ***** *** ********* *** |
| ********* ***** ***        |
| ************** ********    |
| ****** ******** ********   |
| *****************          |
| ************** ***** ***** |

我想你们明白了。

现在,我得到了类似的东西,但它并没有完全满足我的需要。

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);
}

这看起来更像:

| ***** **** ******** **** |
| ****       ********      |
| *******    ******        |

所以我也在尝试获取每个TextView 的宽度,以便我可以手动计算空格并相应地添加项目,但这也失败了,因为尺寸仍然是0,因为它们没有被绘制。所以看来我必须相应地使用 API 来获得所需的行为。

我还是这个GridLayout 的新手,而且 api 很大,所以你们能帮帮我吗?

【问题讨论】:

  • 我实现了同样的事情,但由于某种原因需要很长时间才能绘制或必须在添加到“flowlayout”之前绘制。您可以使用此小部件 github.com/ApmeM/android-flowlayout 。你也可以试试交错网格布局管理器inducesmile.com/android/…
  • 你实现了我发布的代码?或者您是否实施了类似的解决方案?因为它在我的手机上运行得非常顺利。
  • 一个类似的解决方案,但我从服务器获取文本并动态构建您的情况下的按钮或标签。但是,如果不先绘制它们,我将无法知道每个项目的大小。所以我有点想办法在背景中绘制它们,然后我开始将它们添加到真正的“流布局”中,如果屏幕上有足够的空间来显示,则将它们添加到行中,如果没有的话,我会创建一个新行。显然这效率不高,所以我结束了使用那个小部件,但我想来看看人们是如何设法解决这个问题的 :)。
  • 啊,我明白了,呵呵,谢谢你的图书馆,会检查那个,如果效果更好,我可能会切换
  • 我认为我唯一需要做的就是您的 createNewTag() 方法从那里获取项目宽度,而不必先在屏幕上绘制它,干得好。图书馆很有趣,并且有一些方法可以控制物品的重力和那种东西。祝你有美好的一天!。

标签: java android android-gridlayout


【解决方案1】:

好吧,我设法通过计算需要多少空间以及剩余多少空间来解决我自己的问题。当标签插入的空间太少时,它会转到下一行。

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);
    }
}

使用以下内容创建和测量标签:

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 是这样计算的:

DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
deviceWidth = metrics.widthPixels;
deviceHeight = metrics.heightPixels;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-20
    • 2017-06-29
    • 1970-01-01
    • 2017-01-08
    • 2017-07-28
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多