Created
March 12, 2016 16:55
-
-
Save deveshmittal/6899d7e7907ad3945e77 to your computer and use it in GitHub Desktop.
FlowLayout.java
This file contains hidden or 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
| public class FlowLayout extends ViewGroup { | |
| public static final int HORIZONTAL = 0; | |
| public static final int VERTICAL = 1; | |
| private int horizontalSpacing = 0; | |
| private int verticalSpacing = 0; | |
| private int orientation = 0; | |
| private boolean debugDraw = false; | |
| public FlowLayout(Context context) { | |
| super(context); | |
| this.readStyleParameters(context, null); | |
| this.horizontalSpacing = dptopx(15); | |
| this.verticalSpacing = dptopx(10); | |
| } | |
| public FlowLayout(Context context, AttributeSet attributeSet) { | |
| super(context, attributeSet); | |
| this.readStyleParameters(context, attributeSet); | |
| } | |
| public FlowLayout(Context context, AttributeSet attributeSet, int defStyle) { | |
| super(context, attributeSet, defStyle); | |
| this.readStyleParameters(context, attributeSet); | |
| } | |
| private int dptopx(int dp) | |
| { | |
| DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); | |
| return (int)((dp * displayMetrics.density) + 0.5); | |
| } | |
| @Override | |
| protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
| int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft(); | |
| int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft(); | |
| int modeWidth = MeasureSpec.getMode(widthMeasureSpec); | |
| int modeHeight = MeasureSpec.getMode(heightMeasureSpec); | |
| int size; | |
| int mode; | |
| if (orientation == HORIZONTAL) { | |
| size = sizeWidth; | |
| mode = modeWidth; | |
| } else { | |
| size = sizeHeight; | |
| mode = modeHeight; | |
| } | |
| int lineThicknessWithSpacing = 0; | |
| int lineThickness = 0; | |
| int lineLengthWithSpacing = 0; | |
| int lineLength; | |
| int prevLinePosition = 0; | |
| int controlMaxLength = 0; | |
| int controlMaxThickness = 0; | |
| final int count = getChildCount(); | |
| for (int i = 0; i < count; i++) { | |
| final View child = getChildAt(i); | |
| if (child.getVisibility() == GONE) { | |
| continue; | |
| } | |
| child.measure( | |
| MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeWidth), | |
| MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeHeight) | |
| ); | |
| LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
| int hSpacing = this.getHorizontalSpacing(lp); | |
| int vSpacing = this.getVerticalSpacing(lp); | |
| /* hSpacing = 18; | |
| vSpacing = 13;*/ | |
| int childWidth = child.getMeasuredWidth(); | |
| int childHeight = child.getMeasuredHeight(); | |
| int childLength; | |
| int childThickness; | |
| int spacingLength; | |
| int spacingThickness; | |
| if (orientation == HORIZONTAL) { | |
| childLength = childWidth; | |
| childThickness = childHeight; | |
| spacingLength = hSpacing; | |
| spacingThickness = vSpacing; | |
| } else { | |
| childLength = childHeight; | |
| childThickness = childWidth; | |
| spacingLength = vSpacing; | |
| spacingThickness = hSpacing; | |
| } | |
| lineLength = lineLengthWithSpacing + childLength; | |
| lineLengthWithSpacing = lineLength + spacingLength; | |
| boolean newLine = lp.newLine || (mode != MeasureSpec.UNSPECIFIED && lineLength > size); | |
| if (newLine) { | |
| prevLinePosition = prevLinePosition + lineThicknessWithSpacing; | |
| lineThickness = childThickness; | |
| lineLength = childLength; | |
| lineThicknessWithSpacing = childThickness + spacingThickness; | |
| lineLengthWithSpacing = lineLength + spacingLength; | |
| } | |
| lineThicknessWithSpacing = Math.max(lineThicknessWithSpacing, childThickness + spacingThickness); | |
| lineThickness = Math.max(lineThickness, childThickness); | |
| int posX; | |
| int posY; | |
| if (orientation == HORIZONTAL) { | |
| posX = getPaddingLeft() + lineLength - childLength; | |
| posY = getPaddingTop() + prevLinePosition; | |
| } else { | |
| posX = getPaddingLeft() + prevLinePosition; | |
| posY = getPaddingTop() + lineLength - childHeight; | |
| } | |
| lp.setPosition(posX, posY); | |
| controlMaxLength = Math.max(controlMaxLength, lineLength); | |
| controlMaxThickness = prevLinePosition + lineThickness; | |
| } | |
| /* need to take far side padding into account */ | |
| if (orientation == HORIZONTAL) { | |
| controlMaxLength += getPaddingRight(); | |
| controlMaxThickness += getPaddingBottom(); | |
| } else { | |
| controlMaxLength += getPaddingBottom(); | |
| controlMaxThickness += getPaddingRight(); | |
| } | |
| if (orientation == HORIZONTAL) { | |
| this.setMeasuredDimension(resolveSize(controlMaxLength, widthMeasureSpec), resolveSize(controlMaxThickness, heightMeasureSpec)); | |
| } else { | |
| this.setMeasuredDimension(resolveSize(controlMaxThickness, widthMeasureSpec), resolveSize(controlMaxLength, heightMeasureSpec)); | |
| } | |
| } | |
| private int getVerticalSpacing(LayoutParams lp) { | |
| int vSpacing; | |
| if (lp.verticalSpacingSpecified()) { | |
| vSpacing = lp.verticalSpacing; | |
| } else { | |
| vSpacing = this.verticalSpacing; | |
| } | |
| return vSpacing; | |
| } | |
| private int getHorizontalSpacing(LayoutParams lp) { | |
| int hSpacing; | |
| if (lp.horizontalSpacingSpecified()) { | |
| hSpacing = lp.horizontalSpacing; | |
| } else { | |
| hSpacing = this.horizontalSpacing; | |
| } | |
| return hSpacing; | |
| } | |
| @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); | |
| this.drawDebugInfo(canvas, child); | |
| 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 attributeSet) { | |
| return new LayoutParams(getContext(), attributeSet); | |
| } | |
| @Override | |
| protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { | |
| return new LayoutParams(p); | |
| } | |
| private void readStyleParameters(Context context, AttributeSet attributeSet) { | |
| TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout); | |
| try { | |
| horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0); | |
| verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0); | |
| orientation = a.getInteger(R.styleable.FlowLayout_orientation, HORIZONTAL); | |
| debugDraw = a.getBoolean(R.styleable.FlowLayout_debugDraw, false); | |
| } finally { | |
| a.recycle(); | |
| } | |
| } | |
| private void drawDebugInfo(Canvas canvas, View child) { | |
| if (!debugDraw) { | |
| return; | |
| } | |
| Paint childPaint = this.createPaint(0xffffff00); | |
| Paint layoutPaint = this.createPaint(0xff00ff00); | |
| Paint newLinePaint = this.createPaint(0xffff0000); | |
| 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, x + lp.horizontalSpacing, y, childPaint); | |
| canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y - 4.0f, x + lp.horizontalSpacing, y, childPaint); | |
| canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y + 4.0f, x + lp.horizontalSpacing, y, childPaint); | |
| } else if (this.horizontalSpacing > 0) { | |
| float x = child.getRight(); | |
| float y = child.getTop() + child.getHeight() / 2.0f; | |
| canvas.drawLine(x, y, x + this.horizontalSpacing, y, layoutPaint); | |
| canvas.drawLine(x + this.horizontalSpacing - 4.0f, y - 4.0f, x + this.horizontalSpacing, y, layoutPaint); | |
| canvas.drawLine(x + this.horizontalSpacing - 4.0f, y + 4.0f, x + this.horizontalSpacing, y, layoutPaint); | |
| } | |
| if (lp.verticalSpacing > 0) { | |
| float x = child.getLeft() + child.getWidth() / 2.0f; | |
| float y = child.getBottom(); | |
| canvas.drawLine(x, y, x, y + lp.verticalSpacing, childPaint); | |
| canvas.drawLine(x - 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint); | |
| canvas.drawLine(x + 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint); | |
| } else if (this.verticalSpacing > 0) { | |
| float x = child.getLeft() + child.getWidth() / 2.0f; | |
| float y = child.getBottom(); | |
| canvas.drawLine(x, y, x, y + this.verticalSpacing, layoutPaint); | |
| canvas.drawLine(x - 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint); | |
| canvas.drawLine(x + 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint); | |
| } | |
| if (lp.newLine) { | |
| if (orientation == HORIZONTAL) { | |
| float x = child.getLeft(); | |
| float y = child.getTop() + child.getHeight() / 2.0f; | |
| canvas.drawLine(x, y - 6.0f, x, y + 6.0f, newLinePaint); | |
| } else { | |
| float x = child.getLeft() + child.getWidth() / 2.0f; | |
| float y = child.getTop(); | |
| canvas.drawLine(x - 6.0f, y, x + 6.0f, y, newLinePaint); | |
| } | |
| } | |
| } | |
| private Paint createPaint(int color) { | |
| Paint paint = new Paint(); | |
| paint.setAntiAlias(true); | |
| paint.setColor(color); | |
| paint.setStrokeWidth(2.0f); | |
| return paint; | |
| } | |
| public static class LayoutParams extends ViewGroup.LayoutParams { | |
| private static int NO_SPACING = -1; | |
| private int x; | |
| private int y; | |
| private int horizontalSpacing = NO_SPACING; | |
| private int verticalSpacing = NO_SPACING; | |
| private boolean newLine = false; | |
| public LayoutParams(Context context, AttributeSet attributeSet) { | |
| super(context, attributeSet); | |
| this.readStyleParameters(context, attributeSet); | |
| } | |
| public LayoutParams(int width, int height) { | |
| super(width, height); | |
| } | |
| public LayoutParams(ViewGroup.LayoutParams layoutParams) { | |
| super(layoutParams); | |
| } | |
| public boolean horizontalSpacingSpecified() { | |
| return horizontalSpacing != NO_SPACING; | |
| } | |
| public boolean verticalSpacingSpecified() { | |
| return verticalSpacing != NO_SPACING; | |
| } | |
| public void setPosition(int x, int y) { | |
| this.x = x; | |
| this.y = y; | |
| } | |
| private void readStyleParameters(Context context, AttributeSet attributeSet) { | |
| TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams); | |
| try { | |
| horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, NO_SPACING); | |
| verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_verticalSpacing, NO_SPACING); | |
| newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false); | |
| } finally { | |
| a.recycle(); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment