是否可以为Android的LinearLayout设置属性,以使其能够正确包装子控件?
含义-我的孩子数量可变,想像这样水平布置孩子:
示例:Control1,Control2,Control3,...
我这样做是通过设置:
ll.setOrientation(LinearLayout.HORIZONTAL); foreach(儿童中的儿童c) ll.addView(c);
但是,如果我有很多孩子,则最后一个孩子会被切除,而不是转到下一行。
任何想法如何解决?
是否可以为Android的LinearLayout设置属性,以使其能够正确包装子控件?
含义-我的孩子数量可变,想像这样水平布置孩子:
示例:Control1,Control2,Control3,...
我这样做是通过设置:
ll.setOrientation(LinearLayout.HORIZONTAL); foreach(儿童中的儿童c) ll.addView(c);
但是,如果我有很多孩子,则最后一个孩子会被切除,而不是转到下一行。
任何想法如何解决?
Answers:
截至2016年5月,Google已经创建了自己的FlexBoxLayout解决方案,可以解决您的问题。
您可以在此处找到GitHub存储库:https : //github.com/google/flexbox-layout
这应该是您想要的:
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
*
* @author RAW
*/
public class FlowLayout extends ViewGroup {
private int line_height;
public static class LayoutParams extends ViewGroup.LayoutParams {
public final int horizontal_spacing;
public final int vertical_spacing;
/**
* @param horizontal_spacing Pixels between items, horizontally
* @param vertical_spacing Pixels between items, vertically
*/
public LayoutParams(int horizontal_spacing, int vertical_spacing) {
super(0, 0);
this.horizontal_spacing = horizontal_spacing;
this.vertical_spacing = vertical_spacing;
}
}
public FlowLayout(Context context) {
super(context);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);
final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
final int count = getChildCount();
int line_height = 0;
int xpos = getPaddingLeft();
int ypos = getPaddingTop();
int childHeightMeasureSpec;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
} else {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
final int childw = child.getMeasuredWidth();
line_height = Math.max(line_height, child.getMeasuredHeight() + lp.vertical_spacing);
if (xpos + childw > width) {
xpos = getPaddingLeft();
ypos += line_height;
}
xpos += childw + lp.horizontal_spacing;
}
}
this.line_height = line_height;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
height = ypos + line_height;
} else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
if (ypos + line_height < height) {
height = ypos + line_height;
}
}
setMeasuredDimension(width, height);
}
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(1, 1); // default of 1px spacing
}
@Override
protected android.view.ViewGroup.LayoutParams generateLayoutParams(
android.view.ViewGroup.LayoutParams p) {
return new LayoutParams(1, 1, p);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
if (p instanceof LayoutParams) {
return true;
}
return false;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
final int width = r - l;
int xpos = getPaddingLeft();
int ypos = getPaddingTop();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final int childw = child.getMeasuredWidth();
final int childh = child.getMeasuredHeight();
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (xpos + childw > width) {
xpos = getPaddingLeft();
ypos += line_height;
}
child.layout(xpos, ypos, xpos + childw, ypos + childh);
xpos += childw + lp.horizontal_spacing;
}
}
}
}
和XML文件
/* you must write your package name and class name */
<org.android.FlowLayout
android:id="@+id/flow_layout"
android:layout_marginLeft="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
ClassCastException。发生此异常的原因是从另一个Stackoverflow问题stackoverflow.com/q/549451/1741542复制不完整。如果添加generateLayoutParams(ViewGroup.LayoutParams p)方法,它将按预期工作。
new LayoutParams(1, 1, p),不知道人们为什么不尝试代码就
对于需要这种行为的任何人:
private void populateLinks(LinearLayout ll, ArrayList<Sample> collection, String header) {
Display display = getWindowManager().getDefaultDisplay();
int maxWidth = display.getWidth() - 10;
if (collection.size() > 0) {
LinearLayout llAlso = new LinearLayout(this);
llAlso.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
llAlso.setOrientation(LinearLayout.HORIZONTAL);
TextView txtSample = new TextView(this);
txtSample.setText(header);
llAlso.addView(txtSample);
txtSample.measure(0, 0);
int widthSoFar = txtSample.getMeasuredWidth();
for (Sample samItem : collection) {
TextView txtSamItem = new TextView(this, null,
android.R.attr.textColorLink);
txtSamItem.setText(samItem.Sample);
txtSamItem.setPadding(10, 0, 0, 0);
txtSamItem.setTag(samItem);
txtSamItem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TextView self = (TextView) v;
Sample ds = (Sample) self.getTag();
Intent myIntent = new Intent();
myIntent.putExtra("link_info", ds.Sample);
setResult("link_clicked", myIntent);
finish();
}
});
txtSamItem.measure(0, 0);
widthSoFar += txtSamItem.getMeasuredWidth();
if (widthSoFar >= maxWidth) {
ll.addView(llAlso);
llAlso = new LinearLayout(this);
llAlso.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
llAlso.setOrientation(LinearLayout.HORIZONTAL);
llAlso.addView(txtSamItem);
widthSoFar = txtSamItem.getMeasuredWidth();
} else {
llAlso.addView(txtSamItem);
}
}
ll.addView(llAlso);
}
}
这是一个老问题,但是如果有人在这里结束,那么两个库就可以做到这一点:
寻找类似但更简单的问题的解决方案,即将子文本内容包装在水平布局中。kape123的解决方案工作正常。但是,使用ClickableSpan查找一个更简单的解决此问题的方法。也许对一些简单的情况有用。片段:
String[] stringSource = new String[sourceList.size()];
for (int i = 0; c < sourceList.size(); i++) {
String text = sourceList.get(i);
stringSource[i] = text;
}
SpannableString totalContent = new SpannableString(TextUtils.join(",", stringSource));
int start = 0;
for (int j = 0; j < stringSource.length(); j++) {
final String text = stringSource[j];
ClickableSpan span = new ClickableSpan() {
@Override
public void updateDrawState(TextPaint ds) {
ds.setUnderlineText(true);
ds.setColor(getResources().getColor(R.color.green));
}
@Override
public void onClick(View widget) {
// the text clicked
}
};
int end = (start += text.length());
totalContent.setSpan(span, start, end, 0);
star = end + 1;
}
TextView wrapperView = (TextView) findViewById(horizontal_container_id);
wrapperView.setMovementMethod(LinkMovementMethod.getInstance());
wrapperView.setText(totalContent, BufferType.SPANNABLE);
}
Randy Sugianto'Yuku的答案的代码的修改版本,以及我最终得到的内容:
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.View.MeasureSpec.*
import android.view.ViewGroup
import androidx.core.content.withStyledAttributes
import androidx.core.view.children
import *.*.*.R
class FlowLayout(context: Context, attributeSet: AttributeSet) : ViewGroup(context, attributeSet) {
private var lineHeight: Int = 0
private var horizontalSpacing = 0F
private var verticalSpacing = 0F
init {
context.withStyledAttributes(attributeSet, R.styleable.FlowLayout) {
horizontalSpacing = getDimension(R.styleable.FlowLayout_horizontalSpacing, 0F)
verticalSpacing = getDimension(R.styleable.FlowLayout_verticalSpacing, 0F)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = getSize(widthMeasureSpec) - paddingLeft - paddingRight
var height = getSize(heightMeasureSpec) - paddingTop - paddingBottom
var xPosition = paddingLeft
var yPosition = paddingTop
val childHeightMeasureSpec = makeMeasureSpec(
height, if (getMode(heightMeasureSpec) == AT_MOST) AT_MOST else UNSPECIFIED
)
children.forEach { child ->
if (child.visibility != GONE) {
val layoutParams = child.layoutParams as LayoutParamsWithSpacing
child.measure(makeMeasureSpec(width, AT_MOST), childHeightMeasureSpec)
val childWidth = child.measuredWidth
lineHeight =
Math.max(lineHeight, child.measuredHeight + layoutParams.verticalSpacing)
if (xPosition + childWidth > width) {
xPosition = paddingLeft
yPosition += lineHeight
}
xPosition += childWidth + layoutParams.horizontalSpacing
}
}
if (getMode(heightMeasureSpec) == UNSPECIFIED ||
getMode(heightMeasureSpec) == AT_MOST && yPosition + lineHeight < height
) {
height = yPosition + lineHeight
}
setMeasuredDimension(width, height)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
val width = right - left
var xPosition = paddingLeft
var yPosition = paddingTop
children.forEach { child ->
if (child.visibility != View.GONE) {
val layoutParams = child.layoutParams as LayoutParamsWithSpacing
val childWidth = child.measuredWidth
if (xPosition + childWidth > width) {
xPosition = paddingLeft
yPosition += lineHeight
}
child.layout(
xPosition, yPosition, xPosition + childWidth,
yPosition + child.measuredHeight
)
xPosition += layoutParams.horizontalSpacing
xPosition += childWidth
}
}
}
override fun generateDefaultLayoutParams(): ViewGroup.LayoutParams =
LayoutParamsWithSpacing(1, 1)
override fun generateLayoutParams(layoutParams: LayoutParams) =
LayoutParamsWithSpacing(horizontalSpacing.toInt(), verticalSpacing.toInt())
override fun checkLayoutParams(layoutParams: LayoutParams) =
layoutParams is LayoutParamsWithSpacing
class LayoutParamsWithSpacing(val horizontalSpacing: Int, val verticalSpacing: Int) :
ViewGroup.LayoutParams(0, 0)
}
在style / attrs.xml文件中:
<resources>
<declare-styleable name="FlowLayout">
<attr name="horizontalSpacing" format="dimension" />
<attr name="verticalSpacing" format="dimension" />
</declare-styleable>
</resources>
用法:
<*.*.*.*.FlowLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:horizontalSpacing="8dp"
app:verticalSpacing="8dp">
<!-- ... -->
</*.*.*.*.FlowLayout>
//this method will add image view to liner grid and warp it if no space in new child LinearLayout grid
private void addImageToLinyerLayout(LinearLayout ll , ImageView v)
{
//set the padding and margin and weight
v.setPadding(5, 5, 5, 5);
Display display = getWindowManager().getDefaultDisplay();
int maxWidth = display.getWidth() - 10;
int maxChildeNum = (int) ( maxWidth / (110)) ;
Toast.makeText(getBaseContext(), "c" + v.getWidth() ,
Toast.LENGTH_LONG).show();
//loop through all child of the LinearLayout
for (int i = 0; i < ll.getChildCount(); i++) {
View chidv = ll.getChildAt(i);
Class c = chidv.getClass();
if (c == LinearLayout.class) {
//here we are in the child lay out check to add the imageView if there is space
//Available else we will add it to new linear layout
LinearLayout chidvL = (LinearLayout)chidv;
if(chidvL.getChildCount() < maxChildeNum)
{
chidvL.addView(v);
return;
}
} else{
continue;
}
}
//if you reached here this means there was no roam for adding view so we will
//add new linear layout
LinearLayout childLinyer = new LinearLayout(this);
childLinyer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
childLinyer.setOrientation(LinearLayout.HORIZONTAL);
ll.addView(childLinyer);
childLinyer.addView(v);
}
上面的方法将像agrid并排添加imgeview并在您的布局中
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/imageslayout"
></LinearLayout>
我发布此解决方案可能会有所帮助,并节省一些时间,然后在我的应用中使用它
我最终使用了TagView:
<com.cunoraz.tagview.TagView
android:id="@+id/tag_group"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" />
TagView tagGroup = (TagView)findviewById(R.id.tag_view);
//You can add one tag
tagGroup.addTag(Tag tag);
//You can add multiple tag via ArrayList
tagGroup.addTags(ArrayList<Tag> tags);
//Via string array
addTags(String[] tags);
//set click listener
tagGroup.setOnTagClickListener(new OnTagClickListener() {
@Override
public void onTagClick(Tag tag, int position) {
}
});
//set delete listener
tagGroup.setOnTagDeleteListener(new OnTagDeleteListener() {
@Override
public void onTagDeleted(final TagView view, final Tag tag, final int position) {
}
});
Google提供了自己的解决方案:FlowLayout类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.google.android.material.internal;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.core.view.MarginLayoutParamsCompat;
import androidx.core.view.ViewCompat;
import com.google.android.material.R.styleable;
@RestrictTo({Scope.LIBRARY_GROUP})
public class FlowLayout extends ViewGroup {
private int lineSpacing;
private int itemSpacing;
private boolean singleLine;
public FlowLayout(Context context) {
this(context, (AttributeSet)null);
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.singleLine = false;
this.loadFromAttributes(context, attrs);
}
@TargetApi(21)
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
this.singleLine = false;
this.loadFromAttributes(context, attrs);
}
private void loadFromAttributes(Context context, AttributeSet attrs) {
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, styleable.FlowLayout, 0, 0);
this.lineSpacing = array.getDimensionPixelSize(styleable.FlowLayout_lineSpacing, 0);
this.itemSpacing = array.getDimensionPixelSize(styleable.FlowLayout_itemSpacing, 0);
array.recycle();
}
protected int getLineSpacing() {
return this.lineSpacing;
}
protected void setLineSpacing(int lineSpacing) {
this.lineSpacing = lineSpacing;
}
protected int getItemSpacing() {
return this.itemSpacing;
}
protected void setItemSpacing(int itemSpacing) {
this.itemSpacing = itemSpacing;
}
protected boolean isSingleLine() {
return this.singleLine;
}
public void setSingleLine(boolean singleLine) {
this.singleLine = singleLine;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int maxWidth = widthMode != -2147483648 && widthMode != 1073741824 ? 2147483647 : width;
int childLeft = this.getPaddingLeft();
int childTop = this.getPaddingTop();
int childBottom = childTop;
int maxChildRight = 0;
int maxRight = maxWidth - this.getPaddingRight();
int finalWidth;
for(finalWidth = 0; finalWidth < this.getChildCount(); ++finalWidth) {
View child = this.getChildAt(finalWidth);
if (child.getVisibility() != 8) {
this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
LayoutParams lp = child.getLayoutParams();
int leftMargin = 0;
int rightMargin = 0;
if (lp instanceof MarginLayoutParams) {
MarginLayoutParams marginLp = (MarginLayoutParams)lp;
leftMargin += marginLp.leftMargin;
rightMargin += marginLp.rightMargin;
}
int childRight = childLeft + leftMargin + child.getMeasuredWidth();
if (childRight > maxRight && !this.isSingleLine()) {
childLeft = this.getPaddingLeft();
childTop = childBottom + this.lineSpacing;
}
childRight = childLeft + leftMargin + child.getMeasuredWidth();
childBottom = childTop + child.getMeasuredHeight();
if (childRight > maxChildRight) {
maxChildRight = childRight;
}
childLeft += leftMargin + rightMargin + child.getMeasuredWidth() + this.itemSpacing;
}
}
finalWidth = getMeasuredDimension(width, widthMode, maxChildRight);
int finalHeight = getMeasuredDimension(height, heightMode, childBottom);
this.setMeasuredDimension(finalWidth, finalHeight);
}
private static int getMeasuredDimension(int size, int mode, int childrenEdge) {
switch(mode) {
case -2147483648:
return Math.min(childrenEdge, size);
case 1073741824:
return size;
default:
return childrenEdge;
}
}
protected void onLayout(boolean sizeChanged, int left, int top, int right, int bottom) {
if (this.getChildCount() != 0) {
boolean isRtl = ViewCompat.getLayoutDirection(this) == 1;
int paddingStart = isRtl ? this.getPaddingRight() : this.getPaddingLeft();
int paddingEnd = isRtl ? this.getPaddingLeft() : this.getPaddingRight();
int childStart = paddingStart;
int childTop = this.getPaddingTop();
int childBottom = childTop;
int maxChildEnd = right - left - paddingEnd;
for(int i = 0; i < this.getChildCount(); ++i) {
View child = this.getChildAt(i);
if (child.getVisibility() != 8) {
LayoutParams lp = child.getLayoutParams();
int startMargin = 0;
int endMargin = 0;
if (lp instanceof MarginLayoutParams) {
MarginLayoutParams marginLp = (MarginLayoutParams)lp;
startMargin = MarginLayoutParamsCompat.getMarginStart(marginLp);
endMargin = MarginLayoutParamsCompat.getMarginEnd(marginLp);
}
int childEnd = childStart + startMargin + child.getMeasuredWidth();
if (!this.singleLine && childEnd > maxChildEnd) {
childStart = paddingStart;
childTop = childBottom + this.lineSpacing;
}
childEnd = childStart + startMargin + child.getMeasuredWidth();
childBottom = childTop + child.getMeasuredHeight();
if (isRtl) {
child.layout(maxChildEnd - childEnd, childTop, maxChildEnd - childStart - startMargin, childBottom);
} else {
child.layout(childStart + startMargin, childTop, childEnd, childBottom);
}
childStart += startMargin + endMargin + child.getMeasuredWidth() + this.itemSpacing;
}
}
}
}
}
该类的工作原理与上述FlowLayout类类似,但是您不应在项目中添加任何新类,并且与该类相比,设计器使用该类的效果更好
我想要一个非常灵活的简单解决方案(这就是为什么我使用LinearLayouts的原因)。这就是我想出的。
https://github.com/ShalakoSnell/Wrapping_Linear_Layout
注意:我提供了一个使用textviews的示例方法(请参阅textViewArrayListForExample())XML只是具有ID和垂直方向的父视图LinearLayout,不需要其他任何操作。使用方法:传递封装在LinearLayouts中的视图数组以及父视图和上下文。(请参见viewAdapterArrayList(ArrayList textViews))
传入LinearLines数组是使此方法如此灵活的原因,因为它允许您添加不同的视图类型。因此,在第一个LinearLayout中,您可以有文本,在第二个中,您可以有一个图像,然后在第三个中,您可以有一个按钮,依此类推...
肖像示例 横向示例 verticalLinearLayout中的50dp边距 (抱歉,我不能添加图片尚未...看到的链接。
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new WrappingLinearLayout(
viewAdapterArrayList(textViewArrayListForExample()), // <-- replace this with you own array of LinearLayouts
(LinearLayout) findViewById(R.id.verticalLinearLayout),
this);
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/verticalLinearLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</LinearLayout>
包装线性布局
package com.example.wrapping_linear_layout;
import android.content.Context;
import android.widget.LinearLayout;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
public class WrappingLinearLayout {
public WrappingLinearLayout(@NotNull final ArrayList<LinearLayout> views, @NotNull final LinearLayout verticalLinearLayout, @NotNull final Context context) {
verticalLinearLayout.post(new Runnable() {
@Override
public void run() {
execute(views, verticalLinearLayout, context);
}
});
}
private void execute(@NotNull ArrayList<LinearLayout> views, @NotNull final LinearLayout verticalLinearLayout, @NotNull final Context context) {
ArrayList<LinearLayout> horizontalLinearLayouts = new ArrayList<>();
LinearLayout horizontalLinearLayout = new LinearLayout(context);
horizontalLinearLayouts.add(horizontalLinearLayout);
int verticalLinearLayoutWidth = verticalLinearLayout.getMeasuredWidth()
- (verticalLinearLayout.getPaddingLeft()
+ verticalLinearLayout.getPaddingRight());
int totalWidthOfViews = 0;
for (LinearLayout view : views) {
view.measure(0, 0);
int currentViewWidth = view.getMeasuredWidth();
if (totalWidthOfViews + view.getMeasuredWidth() > verticalLinearLayoutWidth) {
horizontalLinearLayout = new LinearLayout(context);
horizontalLinearLayouts.add(horizontalLinearLayout);
totalWidthOfViews = 0;
}
totalWidthOfViews += currentViewWidth;
horizontalLinearLayout.addView(view);
}
for (LinearLayout linearLayout : horizontalLinearLayouts) {
verticalLinearLayout.addView(linearLayout);
}
}
}
private ArrayList<LinearLayout> viewAdapterArrayList(ArrayList<TextView> textViews) {
ArrayList<LinearLayout> views = new ArrayList<>();
for (TextView textView : textViews) {
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.addView(textView);
views.add(linearLayout);
}
return views;
}
private ArrayList<TextView> textViewArrayListForExample() {
ArrayList<TextView> textViews = new ArrayList<>();
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
for (int i = 0; i < 40; i++) {
TextView textView = new TextView(this);
textView.setText("View " + i + " |");
if (i < 20) {
if (i % 5 == 0) {
textView.setText("View longer view " + i + " |");
} else if (i % 7 == 0) {
textView.setText("View different length view " + i + " |");
} else if (i % 9 == 0) {
textView.setText("View very long view that is so long it's really long " + i + " |");
}
}
textView.setMaxLines(1);
textView.setBackground(new ColorDrawable(Color.BLUE));
textView.setTextColor(Color.WHITE);
textView.setLayoutParams(layoutParams);
textView.setPadding(20, 2, 20, 2);
layoutParams.setMargins(10, 2, 10, 2);
textViews.add(textView);
}
return textViews;
}
}
过去,许多自定义解决方案和库都尝试并确实解决了此问题。
从Constraint Layout 2.0现在开始我们可以使用Flow
Flow是用于构建链的新虚拟布局,当它们用完时可以缠绕到下一行甚至屏幕的另一部分。当您在链中布置多个项目时,这很有用,但是您不确定容器在运行时的大小。您可以使用它来根据应用程序中的动态尺寸(例如旋转时的屏幕宽度)构建布局。
这是xml的样子:
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:flow_wrapMode="chain"
app:constraint_referenced_ids="card1, card2, card3"
/>
通知app:constraint_referenced_ids和app:flow_wrapMode属性。
我们使用第一个传递视图,然后选择如何用第二个包装它们。
app:flow_wrapMode 接受3种不同的选项:
无:create a single chain, overflowing if the content doesn’t fit
链条:on overflow, create add another chain for the overflow elements
对齐:similar to chain, but align rows into columns
有关更多详细信息,请查看Android Developers post。
和官方文档