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);
}
}
}