FlowLayout
フローレイアウトを使用するには、Android のカスタム コントロールとして呼び出される Java クラスを作成します。
.../src/FlowLayout.java:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class FlowLayout extends ViewGroup
{
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
private int horizontalSpacing = 20;
private int verticalSpacing = 20;
private int orientation = 0;
private int innerPadding = 12;
public FlowLayout(Context context)
{
super(context);
}
public FlowLayout(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
}
public FlowLayout(Context context, AttributeSet attributeSet, int defStyle)
{
super(context, attributeSet, defStyle);
}
@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()+innerPadding;
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);
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 = innerPadding + getPaddingLeft() + lineLength - childLength;
posY = getPaddingTop() + prevLinePosition;
}
else
{
posX = getPaddingLeft() + prevLinePosition;
posY = innerPadding + getPaddingTop() + lineLength - childHeight;
}
lp.setPosition(posX, posY);
controlMaxLength = Math.max(controlMaxLength, lineLength);
controlMaxThickness = prevLinePosition + lineThickness;
}
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)
{
return super.drawChild(canvas, child, drawingTime);
}
@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);
}
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();
}
}
}
}
次に、フロー レイアウト ビュー内に配置されるビューのカスタム属性を作成します。
.../res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FlowLayout_LayoutParams">
<attr name="layout_newLine" format="boolean"/>
<attr name="layout_horizontalSpacing" format="dimension"/>
<attr name="layout_verticalSpacing" format="dimension"/>
</declare-styleable>
</resources>
次に、xml レイアウトに以下を追加します。
<[PATH_TO_CLASS].FlowLayout
xmlns:flowLayout="http://schemas.android.com/apk/res/za.co.lawdata.searchworks"
android:id="@+id/flow_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
flowLayout:layout_verticalSpacing="50dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
flowLayout:layout_newLine="true"
flowLayout:layout_horizontalSpacing="50dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"/>
</[PATH_TO_CLASS].FlowLayout>
そして、あなたのパッケージパスに置き換え[PATH_TO_CLASS]
てください。com.example.appname
flowLayout:layout_verticalSpacing="50dp"
アイテム間の垂直スペースを設定します。デフォルトは Java クラスで設定されます。
flowLayout:layout_horizontalSpacing="50dp"
アイテム間の水平スペースを設定します。デフォルトは Java クラスで設定されます。
flowLayout:layout_newLine="true"
アイテムを新しい行に配置します。
これは、この git からの編集です: https://github.com/ApmeM/android-flowlayout