首先推荐一篇写的较好的关于View绘制流程的博文,关于View的基础知识大家可以看看https://www.jianshu.com/p/5a71014e7b1b
import android.content.Context; import android.content.res.Resources; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; public class FlowLayout extends ViewGroup { private int mHorizontalSpacing = dp2px(16); //每个item横向间距 private int mVerticalSpacing = dp2px(8); //每个item纵向间距 private List<List<View>> allLines; // 记录所有的行 List<Integer> lineHeights = new ArrayList<>(); // 记录每一行高 public FlowLayout2(Context context) { super(context); } public FlowLayout2(Context context, AttributeSet attrs) { super(context, attrs); } public FlowLayout2(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private void initMeasureParams() { if (allLines !=null && allLines.size() != 0) { allLines.clear(); } else { allLines = new ArrayList<>(); } if (lineHeights !=null && lineHeights.size() != 0) { lineHeights.clear(); } else { lineHeights = new ArrayList<>(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { initMeasureParams(); int childCount = getChildCount(); int paddingLeft = getPaddingLeft();//FlowLayout设置的padding值 int paddingRight = getPaddingRight(); int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); int selfWidth = MeasureSpec.getSize(widthMeasureSpec); int selfHeight = MeasureSpec.getSize(heightMeasureSpec); int lineUsedWidth = 0; int lineHeight = 0; // 行高 int parentNeededWidth = 0; int parentNeededHeight = 0; List<View> lineViews = new ArrayList<>(); for (int i = 0; i< childCount; i++) { View childView = getChildAt(i); LayoutParams childParam = childView.getLayoutParams(); int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight,childParam.width); int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom,childParam.height); childView.measure(childWidthMeasureSpec,childHeightMeasureSpec); int childMeasureWidth = childView.getMeasuredWidth(); int childMeasureHeight = childView.getMeasuredHeight(); if (childMeasureWidth + mHorizontalSpacing + lineUsedWidth >selfWidth) { allLines.add(lineViews); lineHeights.add(lineHeight); parentNeededWidth = Math.max(parentNeededWidth,lineUsedWidth + mHorizontalSpacing); parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing; lineViews = new ArrayList<>(); lineHeight = 0; lineUsedWidth = 0; } lineViews.add(childView); lineUsedWidth = lineUsedWidth + childMeasureWidth + mHorizontalSpacing; lineHeight = Math.max(childMeasureHeight+mVerticalSpacing,lineHeight); if (i == childCount - 1) {//最后一行 lineHeights.add(lineHeight); allLines.add(lineViews); parentNeededWidth = Math.max(parentNeededWidth, lineUsedWidth); parentNeededHeight += lineHeight; } } int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int realWidth = (widthMode == MeasureSpec.EXACTLY) ? selfWidth: parentNeededWidth; int realHeight = (heightMode == MeasureSpec.EXACTLY) ? selfHeight: parentNeededHeight; setMeasuredDimension(realWidth,realHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int lineCount = allLines.size(); int curL = 0; int curT = 0; for(int i = 0;i<lineCount;i++) { List<View> lineViews = allLines.get(i); int lineHeight = lineHeights.get(i); for(int j = 0; j <lineViews.size() ; j++){ View lineView = lineViews.get(j); int left = curL; int top = curT; int right = left + lineView.getMeasuredWidth() ; int bottom = top + lineView.getMeasuredHeight(); lineView.layout(left,top,right,bottom); curL = right + mHorizontalSpacing; } curL = 0; curT = curT + mVerticalSpacing + lineHeight; } } public static int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics()); }