很多App在搜尋頁時都有對熱門标簽的一個排列,而Android官方沒有對應的布局控件,是以自己寫了一個流式布局(也稱标簽布局)--FlowLayout。
為了大家使用的友善,沒有添加自定義屬性,是以需要在代碼中設定下列兩個屬性值:
/**
* 上下行間距
*/
public int veticalSpace = 30;
/**
* Item間距
*/
public int horSpace = 30;
其它的隻需關注填充資料方法setAdapter,及設定點選事件setOnItemClick即可。
先上個效果圖:

貼出完整代碼,複制即用:
package com.custom.widget;
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
public class FlowLayout extends AdapterView<ListAdapter> implements
View.OnClickListener {
private ListAdapter mAdapter;
/**
* 上下行間距
*/
public int veticalSpace = 30;
/**
* Item間距
*/
public int horSpace = 30;
/**
* 每一行有多少個view
*/
private SparseIntArray mLineViews = new SparseIntArray();
private AdapterDataSetObserver mDataSetObserver;
/**
* 一行的高度由最高的item決定
*/
private int lineHeight;
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public ListAdapter getAdapter() {
return mAdapter;
}
@Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
mAdapter = adapter;
if (mAdapter != null) {
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
makeView();
} else {
removeAllViewsInLayout();
invalidate();
}
}
private void makeView() {
removeAllViewsInLayout();
int count = mAdapter.getCount();
for (int i = 0; i < count; i++) {
View child = mAdapter.getView(i, null, this);
LayoutParams params = child.getLayoutParams();
if (params == null)
params = generateDefaultLayoutParams();
addViewInLayout(child, i, params);
}
<span style="white-space:pre"> </span>requestLayout();
}
private class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
super.onChanged();
makeView();
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
int layoutWidth = 0;
int layoutHeight = 0;
int lineWidth = getPaddingLeft() + getPaddingRight();
if (mAdapter == null)
return;
int count = getChildCount();
mLineViews.clear();
int lineCount = 0;
int line = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
lineHeight = Math.max(lineHeight, child.getMeasuredHeight());
int childWidth = child.getMeasuredWidth();
if (lineWidth + childWidth > widthSize) {
mLineViews.put(line, lineCount);
lineWidth -= horSpace;
layoutWidth = Math.max(layoutWidth, lineWidth);
line++;
lineWidth = getPaddingLeft() + getPaddingRight();
lineCount = 0;
}
lineCount++;
lineWidth += childWidth + horSpace;
if (i == count - 1) {
mLineViews.put(line, lineCount);
lineWidth -= horSpace;
layoutWidth = Math.max(layoutWidth, lineWidth);
lineCount = 0;
}
}
if (modeWidth == MeasureSpec.EXACTLY) {
layoutWidth = widthSize;
}
if (modeHeight == MeasureSpec.EXACTLY) {
layoutHeight = heightSize;
} else {
int lines = mLineViews.size();
layoutHeight = getPaddingTop() + getPaddingBottom() + lines
* lineHeight + (lines - 1) * veticalSpace;
}
setMeasuredDimension(layoutWidth, layoutHeight);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
int leftPos = 0;
int topPos = 0;
int lines = mLineViews.size();
int lineCount;
int position = 0;
for (int i = 0; i < lines; i++) {
lineCount = mLineViews.get(i);
View child;
topPos = getPaddingTop() + i * veticalSpace + i * lineHeight;
leftPos = getPaddingLeft();
for (int j = 0; j < lineCount; j++) {
child = getChildAt(position);
if (child == null)
return;
position++;
child.setOnClickListener(this);
int childWidth = child.getMeasuredWidth();
child.layout(leftPos, topPos, leftPos + childWidth, topPos
+ lineHeight);
leftPos += childWidth + horSpace;
}
}
}
@Override
public void onClick(View v) {
int pos = indexOfChild(v);
performItemClick(v, pos, 0);
}
@Override
public void setSelection(int position) {
// TODO Auto-generated method stub
}
@Override
public View getSelectedView() {
// TODO Auto-generated method stub
return null;
}
}