package com.ismaeltoe; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import com.ismaeltoe.flowlayout.R; public class FlowLayout extends ViewGroup { private int mHorizontalPadding; private int mVerticalPadding; public FlowLayout(Context context) { super(context); } public FlowLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public FlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs); } private void init(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout); try { mHorizontalPadding = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalPadding, 0); mVerticalPadding = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalPadding, 0); } finally { a.recycle(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int childLeft = getPaddingLeft(); int childTop = getPaddingTop(); int lineHeight = 0; // 100 is a dummy number, widthMeasureSpec should always be EXACTLY for FlowLayout int myWidth = resolveSize(100, widthMeasureSpec); int wantedHeight = 0; for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); if (child.getVisibility() == View.GONE) { continue; } // let the child measure itself child.measure( getChildMeasureSpec(widthMeasureSpec, 0, child.getLayoutParams().width), getChildMeasureSpec(heightMeasureSpec, 0, child.getLayoutParams().height)); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); // lineheight is the height of current line, should be the height of the heightest view lineHeight = Math.max(childHeight, lineHeight); if (childWidth + childLeft + getPaddingRight() > myWidth) { // wrap this line childLeft = getPaddingLeft(); childTop += mVerticalPadding + lineHeight; lineHeight = childHeight; } childLeft += childWidth + mHorizontalPadding; } wantedHeight += childTop + lineHeight + getPaddingBottom(); setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int childLeft = getPaddingLeft(); int childTop = getPaddingTop(); int lineHeight = 0; int myWidth = right - left; for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); if (child.getVisibility() == View.GONE) { continue; } int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); lineHeight = Math.max(childHeight, lineHeight); if (childWidth + childLeft + getPaddingRight() > myWidth) { childLeft = getPaddingLeft(); childTop += mVerticalPadding + lineHeight; lineHeight = childHeight; } child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); childLeft += childWidth + mHorizontalPadding; } } }