Blob Blame Raw
package com.icystar.dicegenerator;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

/**
 * Left-to-right, then top-to-bottom, layout.
 * 
 * This layout positions its components similarly to writing text on a (Western)
 * page. It goes left to right up to a given width, then wraps to the start of
 * the next line down, and continues. The children get as much space as they ask
 * for.
 * 
 * This layout does not know about justification, and does not put space between
 * children.
 * 
 * WARNING: This is not a complete, robust class. For example, there's no
 * concurrency protection. Also, more methods should be overridden, especially
 * the other addView methods.
 */
public class FlowLayout extends ViewGroup {
	public FlowLayout(Context context) {
		super(context);
	}

	public FlowLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	/**
	 * Holds all component views, in order.
	 */
	private final ArrayList<View> childViews = new ArrayList<View>();
	/**
	 * Holds layout bounds for corresponding child views. This is set in
	 * {@link #onMeasure}, and used in {@link #onLayout}.
	 */
	private final ArrayList<Rect> childPositions = new ArrayList<Rect>();

	/**
	 * Adds a child view to the end of the list of children. Currently 31jan12,
	 * this is the only addView method that should be called.
	 */
	@Override
	public void addView(View child) {
		super.addView(child); // Necessary for event propagation, perhaps other
								// framework stuff.
		childViews.add(child);
		childPositions.add(new Rect());
	}

	@Override
	public void removeAllViews() {
		childViews.clear();
		childPositions.clear();
		super.removeAllViews();
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// //// Extract incoming constraints
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); // This is
																	// our
																	// line-length
																	// limit.
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		//int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
		// //// Measure child views
		int childWidthMode = widthMode == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST
				: widthMode;
		int childHeightMode = heightMode == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST
				: heightMode;
		int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthMode,
				widthMode);
		int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
				childHeightMode, heightMode);
		for (View childView : childViews) {
			childView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
		}
		// //// Position each child
		int acrossPosition = 0; // Rightmost edge of last view on this line.
		int lineTop = 0; // Bottom edge of previous line.
		int lineHeight = 0; // Bottom edge of this line, so far.
		int childCount = childViews.size();
		for (int i = 0; i < childCount; i++) {
			// //// Get required info
			View childView = childViews.get(i);
			Rect childPosition = childPositions.get(i);
			int childWidth = childView.getMeasuredWidth();
			int childHeight = childView.getMeasuredHeight();
			// //// Perhaps start new line
			if (acrossPosition + childWidth > widthSpecSize) {
				// Have filled line, start a new one.
				acrossPosition = 0;
				lineTop += lineHeight;
				lineHeight = 0;
			}
			// //// Place this child, and update progress variables.
			int right = acrossPosition + childWidth;
			childPosition.set(acrossPosition, lineTop, right, lineTop
					+ childHeight);
			acrossPosition = right;
			if (childHeight > lineHeight)
				lineHeight = childHeight;
		}
		// //// Set the WritingLayout's measurements.
		int pageHeight = lineTop + lineHeight;
		this.setMeasuredDimension(widthSpecSize, pageHeight);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// Don't know exactly what the 'changed' argument means.
		int childCount = childViews.size();
		for (int i = 0; i < childCount; i++) {
			View childView = childViews.get(i);
			Rect childPosition = childPositions.get(i);
			childView.layout(childPosition.left, childPosition.top,
					childPosition.right, childPosition.bottom);
		}
	}

}