安卓 - 多行线性布局

55
我需要一个多行布局,它的行为就像水平线性布局一样。当没有足够的空间来放置新的小部件时,它会扩展到下一行,就像文本中的单词一样。小部件会在运行时添加,并且应使用 wrap_content 去适应大小。实际上,这些小部件将是按钮。
是否有任何具有这种行为的小部件?或者可以给出如何编写这种布局的建议。
最终的效果应该是这样的: draft for a multi-line layout

您在一行中想要放置的最大小部件(按钮)数量有限制吗? - PravinCG
不,它们将受到布局宽度和单个小部件大小的限制。 - Raiv
它不已经自动包装了吗?我认为它会自动换行。 - Jack
1
不,它不是这样的。它将小部件大小减少到允许的最小值,并将未适合的所有内容排除在视图之外。 - Raiv
5个回答

23

查看评论:这将完成工作

/*
*  Copyright 2011 Sherif
*/

private void populateText(LinearLayout ll, View[] views , Context mContext) { 
    Display display = getWindowManager().getDefaultDisplay();
    ll.removeAllViews();
    int maxWidth = display.getWidth() - 20;

    LinearLayout.LayoutParams params;
    LinearLayout newLL = new LinearLayout(mContext);
    newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.WRAP_CONTENT));
    newLL.setGravity(Gravity.LEFT);
    newLL.setOrientation(LinearLayout.HORIZONTAL);

    int widthSoFar = 0;

    for (int i = 0 ; i < views.length ; i++ ){
        LinearLayout LL = new LinearLayout(mContext);
        LL.setOrientation(LinearLayout.HORIZONTAL);
        LL.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM);
        LL.setLayoutParams(new ListView.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        //my old code
        //TV = new TextView(mContext);
        //TV.setText(textArray[i]);
        //TV.setTextSize(size);  <<<< SET TEXT SIZE
        //TV.measure(0, 0);
        views[i].measure(0,0);
        params = new LinearLayout.LayoutParams(views[i].getMeasuredWidth(),
                LayoutParams.WRAP_CONTENT);
        //params.setMargins(5, 0, 5, 0);  // YOU CAN USE THIS
        //LL.addView(TV, params);
        LL.addView(views[i], params);
        LL.measure(0, 0);
        widthSoFar += views[i].getMeasuredWidth();// YOU MAY NEED TO ADD THE MARGINS
        if (widthSoFar >= maxWidth) {
            ll.addView(newLL);

            newLL = new LinearLayout(mContext);
            newLL.setLayoutParams(new LayoutParams(
                    LayoutParams.FILL_PARENT,
                    LayoutParams.WRAP_CONTENT));
            newLL.setOrientation(LinearLayout.HORIZONTAL);
            newLL.setGravity(Gravity.LEFT);
            params = new LinearLayout.LayoutParams(LL
                    .getMeasuredWidth(), LL.getMeasuredHeight());
            newLL.addView(LL, params);
            widthSoFar = LL.getMeasuredWidth();
        } else {
            newLL.addView(LL);
        }
    }
    ll.addView(newLL);
}

@AndersMetnik 在代码中已经定义了 (LL = new LinearLayout(mContext);) - Sherif elKhatib
@AndersMetnik 我不确定你是否使用了完全相同的代码,但是这段代码没有问题。当然,你可以使用 ArrayList。views[] 是一个 view 数组,所以你可以像这样使用它: views = new View[3]; views[0] = new TextView(); views[1] = new Bla(); views[2] = new Bla(); - Sherif elKhatib
1
谢谢,提醒大家,记得将ll(原始线性布局)设置为垂直。 - Anders Metnik
@SherifelKhatib 它正确地传播,但是当我使用EditText时,“锁定”它们的大小,因此在输入时它们不会重新调整大小。你知道为什么吗? - Anders Metnik
@AndersMetnik 我认为实现EditText的大小调整和重新排列可能会有些困难。无论如何,EditText没有调整大小是因为我们在这一行中指定了宽度:params = new LinearLayout.LayoutParams(TV.getMeasuredWidth(), LayoutParams.WRAP_CONTENT);params = new LinearLayout.LayoutParams(LL.getMeasuredWidth(), LL.getMeasuredHeight()); - Sherif elKhatib
显示剩余2条评论

19

Sherif的回答很好,但没有处理可能存在在LinearLayout左右两侧的额外视图的情况。我已经更新并清理了代码以处理这种情况:

/**
 * Copyright 2011 Sherif 
 * Updated by Karim Varela to handle LinearLayouts with other views on either side.
 * @param linearLayout
 * @param views : The views to wrap within LinearLayout
 * @param context
 * @param extraView : An extra view that may be to the right or left of your LinearLayout.
 * @author Karim Varela
 **/
private void populateViews(LinearLayout linearLayout, View[] views, Context context, View extraView)
{
    extraView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

    // kv : May need to replace 'getSherlockActivity()' with 'this' or 'getActivity()'
    Display display = getSherlockActivity().getWindowManager().getDefaultDisplay();
    linearLayout.removeAllViews();
    int maxWidth = display.getWidth() - extraView.getMeasuredWidth() - 20;

    linearLayout.setOrientation(LinearLayout.VERTICAL);

    LinearLayout.LayoutParams params;
    LinearLayout newLL = new LinearLayout(context);
    newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    newLL.setGravity(Gravity.LEFT);
    newLL.setOrientation(LinearLayout.HORIZONTAL);

    int widthSoFar = 0;

    for (int i = 0; i < views.length; i++)
    {
        LinearLayout LL = new LinearLayout(context);
        LL.setOrientation(LinearLayout.HORIZONTAL);
        LL.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
        LL.setLayoutParams(new ListView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

        views[i].measure(0, 0);
        params = new LinearLayout.LayoutParams(views[i].getMeasuredWidth(), LayoutParams.WRAP_CONTENT);
        params.setMargins(5, 0, 5, 0);

        LL.addView(views[i], params);
        LL.measure(0, 0);
        widthSoFar += views[i].getMeasuredWidth();
        if (widthSoFar >= maxWidth)
        {
            linearLayout.addView(newLL);

            newLL = new LinearLayout(context);
            newLL.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
            newLL.setOrientation(LinearLayout.HORIZONTAL);
            newLL.setGravity(Gravity.LEFT);
            params = new LinearLayout.LayoutParams(LL.getMeasuredWidth(), LL.getMeasuredHeight());
            newLL.addView(LL, params);
            widthSoFar = LL.getMeasuredWidth();
        }
        else
        {
            newLL.addView(LL);
        }
    }
    linearLayout.addView(newLL);
}

好的回答,我有一个问题,在这个布局中,是否可以删除特定的项目?提前致谢。 - EugenUngurean
是的,LinearLayout 是 ViewGroup 的子类,因此您可以在 LinearLayout 上调用 removeView()。 - Karim Varela
我还可以建议从传递的上下文中检索窗口管理器: WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); - MaiOM
如果您不需要额外的视图,请添加一些代码(if (extraView != null)...) - Volodymyr Kulyk

5

2
假设您拥有Constraint Layout 2.0.0或更高版本,我认为您可以使用一个带有androidx.constraintlayout.helper.widget.Flow子项的ConstraintLayout。Flow可以具有app:flow_wrapMode=chain或aligned,具体取决于您想要的布局外观。
列表中的每个元素都将是Flow的同级项(即嵌套在ConstraintLayout中但没有任何约束条件)。每个元素必须具有id,并且这些id必须在Flow的app:constraint_referenced_ids属性的值中列出。
有关更多信息,请查看以下资源:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接