在外层直接使用TagLayout布局即可。 public class TagLayout extends ViewGroup { // 记录每一行有多高 List<Integer> lineHeights = new ArrayList<>(); List<List<View>> views = new ArrayList<>(); public TagLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { views.clear(); lineHeights.clear(); // 1,计算 // 每一行有多少子控件 该行有多少列数 List<View> lineViews = new ArrayList<>(); int width = getMeasuredWidth(); // 容器自己的宽度 int lineWidth = 0; int lineHeight = 0; // 这一行的最大高度 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width){ // 超出,换行 lineHeights.add(lineHeight); views.add(lineViews); lineWidth = 0; lineViews = new ArrayList<>(); } lineWidth += childWidth + lp.leftMargin + lp.rightMargin; lineHeight = Math.max(lineHeight,childHeight+lp.topMargin + lp.bottomMargin); lineViews.add(child); } lineHeights.add(lineHeight); views.add(lineViews); int left = 0; int top = 0; // 2,摆放 int size = views.size(); for (int i = 0; i < size; i++) { lineViews = this.views.get(i); int size1 = lineViews.size(); lineHeight = lineHeights.get(i); for (int j = 0; j < size1; j++) { // 遍历这一行的所有child View child = lineViews.get(j); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int lc = left + lp.leftMargin; int tc = top + lp.topMargin; int rc = lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); child.layout(lc,tc,rc,bc); left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } left = 0; top += lineHeight; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); int width = 0; // width = 所有行里面最宽的一行 int height = 0; // height = 所有行的高度相加 // 一行的宽度 = 一行当中的所有view宽度的和 一直在累加 int lineWidth = 0; int lineHeight = 0; //1, 测量所有控件的大小 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); measureChild(child,widthMeasureSpec,heightMeasureSpec); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); // 子控件真实占用的宽高 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; // 当一行放不下的时候需要换行 if((lineWidth + childWidth) > sizeWidth){ // 换行 width = Math.max(lineWidth,width); lineWidth = childWidth; height += lineHeight; lineHeight = childHeight; }else { // 累加宽度 lineWidth += childWidth; // 之前最大高度和当前高度的最大值 lineHeight = Math.max(lineHeight,childHeight); } // 最后一步 if (i == childCount -1){ width = Math.max(width,lineWidth); height += lineHeight; } } //2,测量并定义自身的大小 int measuredWidth = (modeWidth == MeasureSpec.EXACTLY)?sizeWidth:width; // wrap_content/match_parent/EXACTLY int measuredHeight = (modeHeight == MeasureSpec.EXACTLY)?sizeHeight:height; // wrap_content/match_parent/EXACTLY setMeasuredDimension(measuredWidth,measuredHeight); } @Override protected LayoutParams generateLayoutParams(LayoutParams p) { return new MarginLayoutParams(p); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(),attrs); } }
// 标签的背景设置 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#AAC261"/> <corners android:radius="5dp"/> <padding android:left="10dp" android:top="2dp" android:right="10dp" android:bottom="2dp"/> </shape>