package org.wikipedia.views;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import org.wikipedia.BuildConfig;
import org.wikipedia.util.DimenUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Implements a "Flow" layout, where child Views are arranged horizontally, and allowed
* to overflow onto multiple "lines".
*/
public class FlowLayout extends ViewGroup {
private static final int HORIZONTAL_SPACING = 8;
private static final int VERTICAL_SPACING = 8;
private Resources resources;
private List<Integer> lineHeights = new ArrayList<>();
public FlowLayout(Context context) {
super(context);
resources = context.getResources();
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
resources = context.getResources();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (BuildConfig.DEBUG && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
throw new AssertionError();
}
int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
int count = getChildCount();
int lineHeight = 0;
int xpos = getPaddingLeft();
int ypos = getPaddingTop();
int childHeightMeasureSpec;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
} else {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
lineHeights.clear();
boolean overflowed = false;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
int childWidth = child.getMeasuredWidth() + (int) DimenUtil.dpToPx(HORIZONTAL_SPACING);
lineHeight = Math.max(lineHeight, child.getMeasuredHeight());
if (xpos + childWidth > width) {
xpos = getPaddingLeft();
lineHeight += (int) DimenUtil.dpToPx(VERTICAL_SPACING);
lineHeights.add(lineHeight);
ypos += lineHeight;
lineHeight = 0;
overflowed = true;
}
xpos += childWidth;
}
}
if (overflowed) {
if (lineHeight > 0) {
lineHeights.add(lineHeight);
} else {
if (getChildCount() > 0) {
lineHeights.add(getChildAt(getChildCount() - 1).getMeasuredHeight() + (int) DimenUtil.dpToPx(VERTICAL_SPACING));
}
}
} else {
if (lineHeight > 0) {
lineHeights.add(lineHeight);
}
}
int totalHeight = 0;
for (int i : lineHeights) {
totalHeight += i;
}
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
height = totalHeight;
} else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
if (totalHeight < height) {
height = totalHeight;
}
}
setMeasuredDimension(width, height);
}
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(0, 0);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p != null;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
int width = r - l;
boolean isRtl = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL;
int xpos = isRtl ? width - getPaddingRight() : getPaddingLeft();
int ypos = getPaddingTop();
int curLine = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
int childw = child.getMeasuredWidth();
int childh = child.getMeasuredHeight();
if (isRtl) {
if (xpos - childw < 0) {
xpos = width - getPaddingRight();
if (lineHeights.size() > curLine) {
ypos += lineHeights.get(curLine++);
}
}
child.layout(xpos - getChildAt(i).getMeasuredWidth(), ypos,
xpos - getChildAt(i).getMeasuredWidth() + childw, ypos + childh);
xpos -= childw + (int) DimenUtil.dpToPx(HORIZONTAL_SPACING);
} else {
if (xpos + childw > width) {
xpos = getPaddingLeft();
if (lineHeights.size() > curLine) {
ypos += lineHeights.get(curLine++);
}
}
child.layout(xpos, ypos, xpos + childw, ypos + childh);
xpos += childw + (int) DimenUtil.dpToPx(HORIZONTAL_SPACING);
}
}
}
}
}