很多的搜索界面都会有类似的布局:好多的标签依次顺序排列,当一行放不下后自动移动到下一行,如图:
示例
这个布局是从网络上找的一个,但是有点bug(子控件数量大于两行会与第二行view重合),我在此基础上进行了修改,在此也谢谢网络上的大神们。
大体思路:
设计一个流布局继承于ViewGroup,实现onMeasure()与onLayout()方法。我们要动态 的添加子View,所以我们还要写一个方法让布局添加我们产生的view。
首先是一个我们添加子View的方法createChild,我们在这个方法里进行view的部分属性的设置 例如他们的padding是多少,margin是多少,文字的居中,点击事件等等。
private void createChild(String[] data, final Context context, int textSize, int pl, int pt, int pr, int pb, int ml, int mt, int mr, int mb){
int size = data.length;
for(int i = 0;i
String text = data[i];
//通过判断style是TextView还是Button进行不同的操作,还可以继续添加不同的view
if (style == TEXTVIEW_STYLE){
btn = new TextView(context);
((TextView) btn).setGravity(Gravity.CENTER);
((TextView) btn).setText(text);
((TextView) btn).setTextSize(textSize);
}else if (style == BUTTON_STYLE){
btn = new Button(context);
((Button) btn).setGravity(Gravity.CENTER);
((Button) btn).setText(text);
((Button) btn).setTextSize(textSize);
}
btn.setClickable(true);
btn.setPadding(dip2px(context, pl),dip2px(context, pt),dip2px(context, pr),dip2px(context, pb));
MarginLayoutParams params = new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT,MarginLayoutParams.WRAP_CONTENT);
params.setMargins(ml, mt, mr, mb);
btn.setLayoutParams(params);
final int finalI = i;
//给每个view添加点击事件
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
markClickListener.clickMark(finalI);
}
});
this.addView(btn);
}
}
我们添加了view之后需要在onLayout方法中测量每个子view 的高度以及每一行的高度和宽度。
//onLayout中完成对所有childView的位置以及大小的指定
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mAllViews.clear(); //清空子控件列表
mLineHeight.clear(); //清空高度记录列表
int width = getWidth();//得到当前控件的宽度(在onmeasure方法中已经测量出来了)
int childCount = getChildCount();
// 存储每一行所有的childView
List lineViews = new ArrayList();
int lineWidth = 0; //行宽
int lineHeight = 0; //总行高
for(int i = 0 ; i
View child = getChildAt(i);
MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();//得到属性参数
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
// 如果已经需要换行
if (i == 3){
i = 3;
}
if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width) //大于父布局的宽度
{
// 记录这一行所有的View以及最大高度
mLineHeight.add(lineHeight);
// 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView
mAllViews.add(lineViews);
lineWidth = 0;// 重置行宽
lineViews = new ArrayList();
}
/**
* 如果不需要换行,则累加
*/
lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
+ lp.bottomMargin);
lineViews.add(child);
}
// 记录最后一行 (因为最后一行肯定大于父布局的宽度,所以添加最后一行是必要的)
mLineHeight.add(lineHeight);
mAllViews.a