Created
May 11, 2016 09:41
-
-
Save vinothkannans/d88bfcfe61a80f4ac3bbad524660fe5c to your computer and use it in GitHub Desktop.
Android Flow Layout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.vinkas.layout; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.view.ViewGroup; | |
public class FlowLayout extends ViewGroup { | |
private int mHorizontalSpacing; | |
private int mVerticalSpacing; | |
private Paint mPaint; | |
public FlowLayout(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout); | |
try { | |
mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0); | |
mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0); | |
} finally { | |
a.recycle(); | |
} | |
mPaint = new Paint(); | |
mPaint.setAntiAlias(true); | |
mPaint.setColor(0xffff0000); | |
mPaint.setStrokeWidth(2.0f); | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
int widthSize = MeasureSpec.getSize(widthMeasureSpec) - getPaddingRight(); | |
int widthMode = MeasureSpec.getMode(widthMeasureSpec); | |
boolean growHeight = widthMode != MeasureSpec.UNSPECIFIED; | |
int width = 0; | |
int height = getPaddingTop(); | |
int currentWidth = getPaddingLeft(); | |
int currentHeight = 0; | |
boolean breakLine = false; | |
boolean newLine = false; | |
int spacing = 0; | |
final int count = getChildCount(); | |
for (int i = 0; i < count; i++) { | |
View child = getChildAt(i); | |
measureChild(child, widthMeasureSpec, heightMeasureSpec); | |
LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
spacing = mHorizontalSpacing; | |
if (lp.horizontalSpacing >= 0) { | |
spacing = lp.horizontalSpacing; | |
} | |
if (growHeight && (breakLine || currentWidth + child.getMeasuredWidth() > widthSize)) { | |
height += currentHeight + mVerticalSpacing; | |
currentHeight = 0; | |
width = Math.max(width, currentWidth - spacing); | |
currentWidth = getPaddingLeft(); | |
newLine = true; | |
} else { | |
newLine = false; | |
} | |
lp.x = currentWidth; | |
lp.y = height; | |
currentWidth += child.getMeasuredWidth() + spacing; | |
currentHeight = Math.max(currentHeight, child.getMeasuredHeight()); | |
breakLine = lp.breakLine; | |
} | |
if (!newLine) { | |
height += currentHeight; | |
width = Math.max(width, currentWidth - spacing); | |
} | |
width += getPaddingRight(); | |
height += getPaddingBottom(); | |
setMeasuredDimension(resolveSize(width, widthMeasureSpec), | |
resolveSize(height, heightMeasureSpec)); | |
} | |
@Override | |
protected void onLayout(boolean changed, int l, int t, int r, int b) { | |
final int count = getChildCount(); | |
for (int i = 0; i < count; i++) { | |
View child = getChildAt(i); | |
LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight()); | |
} | |
} | |
@Override | |
protected boolean drawChild(Canvas canvas, View child, long drawingTime) { | |
boolean more = super.drawChild(canvas, child, drawingTime); | |
LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
if (lp.horizontalSpacing > 0) { | |
float x = child.getRight(); | |
float y = child.getTop() + child.getHeight() / 2.0f; | |
canvas.drawLine(x, y - 4.0f, x, y + 4.0f, mPaint); | |
canvas.drawLine(x, y, x + lp.horizontalSpacing, y, mPaint); | |
canvas.drawLine(x + lp.horizontalSpacing, y - 4.0f, x + lp.horizontalSpacing, y + 4.0f, mPaint); | |
} | |
if (lp.breakLine) { | |
float x = child.getRight(); | |
float y = child.getTop() + child.getHeight() / 2.0f; | |
canvas.drawLine(x, y, x, y + 6.0f, mPaint); | |
canvas.drawLine(x, y + 6.0f, x + 6.0f, y + 6.0f, mPaint); | |
} | |
return more; | |
} | |
@Override | |
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { | |
return p instanceof LayoutParams; | |
} | |
@Override | |
protected LayoutParams generateDefaultLayoutParams() { | |
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); | |
} | |
@Override | |
public LayoutParams generateLayoutParams(AttributeSet attrs) { | |
return new LayoutParams(getContext(), attrs); | |
} | |
@Override | |
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { | |
return new LayoutParams(p.width, p.height); | |
} | |
public static class LayoutParams extends ViewGroup.LayoutParams { | |
int x; | |
int y; | |
public int horizontalSpacing; | |
public boolean breakLine; | |
public LayoutParams(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout_LayoutParams); | |
try { | |
horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, -1); | |
breakLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_breakLine, false); | |
} finally { | |
a.recycle(); | |
} | |
} | |
public LayoutParams(int w, int h) { | |
super(w, h); | |
} | |
} | |
} |
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FlowLayout">
<attr name="horizontalSpacing" format="dimension" />
<attr name="verticalSpacing" format="dimension" />
</declare-styleable>
<declare-styleable name="FlowLayout_LayoutParams">
<attr name="layout_breakLine" format="boolean" />
<attr name="layout_horizontalSpacing" format="dimension" />
</declare-styleable>
</resources>
Usage
<com.vinkas.layout.FlowLayout
xmlns:vinkas="http://schemas.android.com/apk/res/com.vinkas.layout"
xmlns:android="http://schemas.android.com/apk/res/android"
vinkas:horizontalSpacing="6dip"
vinkas:verticalSpacing="12dip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This gist created by a stackoverflow's answer by Romain Guy
BIGGG... thanks to Romain Guy