Back to project page ExpertAndroid.
The source code is released under:
MIT License
If you think the Android project ExpertAndroid listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.iuriio.demos.expertandroid.ch3flowlayout; /*from w w w . j a v a2 s . c o m*/ import android.content.Context; import android.content.res.TypedArray; import android.text.Layout; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; public class FlowLayout extends ViewGroup { private int hspace = 10; private int vspace = 10; public FlowLayout(Context context) { super(context); this.initialize(context); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout, defStyle, 0); this.hspace = t.getDimensionPixelSize(R.styleable.FlowLayout_hspace, this.hspace); this.vspace = t.getDimensionPixelSize(R.styleable.FlowLayout_vspace, this.vspace); t.recycle(); this.initialize(context); } private void initialize(Context context) { } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int childCount = this.getChildCount(); for (int index = 0; index < childCount; index++) { final View child = this.getChildAt(index); LayoutParams lp = (LayoutParams) child.getLayoutParams(); child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight()); } } //This is very basic //doesn't take into account padding //You can easily modify it to account for padding @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int realWidth = MeasureSpec.getSize(widthMeasureSpec); int realHeight = MeasureSpec.getSize(heightMeasureSpec); int currentHeight = 0; int currentWidth = 0; int currentChildHeight = 0; int currentChildWidth = 0; int numOfChildren = this.getChildCount(); for (int index = 0; index < numOfChildren; index++) { View child = this.getChildAt(index); this.measureChild(child, widthMeasureSpec, heightMeasureSpec); int childMeasuredWidth = child.getMeasuredWidth(); int childMeasuredHeight = child.getMeasuredHeight(); if (currentChildWidth + childMeasuredWidth > realWidth) { // new line: max of current width and current width position // when multiple lines are in play w could be maxed out // or in uneven sizes is the max of the right side lines // all lines don't have to have the same width // some may be larger than others currentWidth = Math.max(currentWidth, currentChildWidth); //reposition the point on the next line currentChildWidth = 0; //start of the line currentChildHeight = currentChildHeight + childMeasuredHeight; //add view height to the current height } int nextChildWidth = currentChildWidth + childMeasuredWidth; int nextChildHeight = currentChildHeight; //latest height: current point + height of the view //however if the previous height is larger use that one currentHeight = Math.max(currentHeight, currentChildHeight + childMeasuredHeight); // Save the current coords for the view in its layout LayoutParams lp = (LayoutParams) child.getLayoutParams(); lp.x = currentChildWidth; lp.y = currentChildHeight; currentChildWidth = nextChildWidth; currentChildHeight = nextChildHeight; } currentWidth = Math.max(currentChildWidth, currentWidth); this.setMeasuredDimension( resolveSize(currentWidth, widthMeasureSpec), resolveSize(currentHeight, heightMeasureSpec)); } /** * Returns a new set of layout parameters based on the supplied attributes set. * * @param attrs the attributes to build the layout parameters from * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one * of its descendants */ @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new FlowLayout.LayoutParams(this.getContext(), attrs); } /** * Returns a set of default layout parameters. These parameters are requested * when the View passed to {@link #addView(android.view.View)} has no layout parameters * already set. If null is returned, an exception is thrown from addView. * * @return a set of default layout parameters or null */ @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } /** * Returns a safe set of layout parameters based on the supplied layout params. * When a ViewGroup is passed a View whose layout params do not pass the test of * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method * is invoked. This method should return a new set of layout params suitable for * this ViewGroup, possibly by copying the appropriate attributes from the * specified set of layout params. * * @param p The layout parameters to convert into a suitable set of layout parameters * for this ViewGroup. * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one * of its descendants */ @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p); } /** * {@inheritDoc} * * @param p */ @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof LayoutParams; } public static class LayoutParams extends MarginLayoutParams { public int spacing = -1; public int x = 0; public int y = 0; /** * Creates a new set of layout parameters. The values are extracted from * the supplied attributes set and context. * * @param c the application environment * @param attrs the set of attributes from which to extract the layout */ public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); TypedArray t = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout); this.spacing = t.getDimensionPixelSize(R.styleable.FlowLayout_Layout_layout_space, 0); t.recycle(); } /** * {@inheritDoc} * * @param width * @param height */ public LayoutParams(int width, int height) { super(width, height); this.spacing = 0; } /** * {@inheritDoc} * * @param source */ public LayoutParams(ViewGroup.LayoutParams source) { super(source); } /** * Copy constructor. Clones the width, height and margin values of the source. * * @param source The layout params to copy from. */ public LayoutParams(MarginLayoutParams source) { super(source); } } }