public class FlowLayout extends ViewGroup {
private final String TAG = FlowLayout.class.getSimpleName();
private int dp8 = ScreenAdapter.dp2px(8);
private int dp2 = ScreenAdapter.dp2px(2);
private int dp12 = ScreenAdapter.dp2px(12);
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
//当前ViewGroup的总高度
int totalHeight = 0;
//当前行的总宽度
int currentLineWidth = 0;
//每个childView所占用的宽度
int childViewWidthSpace = 0;
//每个childView所占用的高度
int childViewHeightSpace = 0;
int count = getChildCount();
MarginLayoutParams layoutParams;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {//只有当这个View能够显示的时候才去测量
//测量每个子View,以获取子View的宽和高
measureChild(child, widthMeasureSpec, heightMeasureSpec);
layoutParams = (MarginLayoutParams) child.getLayoutParams();
// 一个view真实占用的宽高
childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
if (totalHeight == 0) {
totalHeight = childViewHeightSpace;
}
//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行
if (currentLineWidth + childViewWidthSpace > widthSize) {
totalHeight += childViewHeightSpace;
//另起一行后,需要重置当前行宽
currentLineWidth = childViewWidthSpace;
} else {//表示当前行可以继续添加子元素
currentLineWidth += childViewWidthSpace;
}
}
}
setMeasuredDimension(widthSize, totalHeight);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//每个childView所占用的宽度
int childViewWidthSpace = 0;
//每个childView所占用的高度
int childViewHeightSpace = 0;
//当前行的总宽度
int currentLineWidth = 0;
int currentTop = 0;
int count = getChildCount();
MarginLayoutParams layoutParams;
LogUtil.i(TAG, "onLayout count " + count);
for (int i = 0; i < count; i++) {
int left = 0, top = 0, right = 0, bottom = 0;
View child = getChildAt(i);
//只有当这个View能够显示的时候才去测量
if (child.getVisibility() != View.GONE) {
layoutParams = (MarginLayoutParams) child.getLayoutParams();
childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行
if (currentLineWidth + childViewWidthSpace > getWidth()) {
// 新的一行 当前行宽就是当前view的宽
currentTop += childViewHeightSpace;
currentLineWidth = childViewWidthSpace;
left = layoutParams.leftMargin;
} else {//表示当前行可以继续添加子元素
left = currentLineWidth + layoutParams.leftMargin;
// 当前宽度要加上新的view了
currentLineWidth += childViewWidthSpace;
}
top = (currentTop + layoutParams.topMargin);
right = left + child.getMeasuredWidth();
bottom = top + child.getMeasuredHeight();
child.layout(left, top, right, bottom);
LogUtil.i(TAG, "layout " + left + " " + top + " " + right + " " + bottom);
}
}
}
/**
* 对外数据接口,不同数据可自己创建新的方法
*
* @param playbills
*/
public void addPlaybill(Activity activity, ArrayList<ThemePlaybillBean> playbills) {
if (playbills == null) {
return;
}
removeAllViews();
for (int i = 0; i < playbills.size(); i++) {
TextView tv = new TextView(getContext());
MarginLayoutParams lp = new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT);
lp.setMargins(0, 0, dp12 , dp12);
tv.setIncludeFontPadding(false);
tv.setLayoutParams(lp);
tv.setBackgroundResource(R.drawable.shape_1afff_round);
/*
* setPadding一定要在setBackgroundResource后面使用才有效!!!
* http://stackoverflow.com/questions/18327498/setting-padding-for-textview-not-working
*/
tv.setPadding(dp8, dp2, dp8, dp2);
tv.setTextColor(0xffffffff);
if(playbills.get(i).title.length() > 8) {
tv.setText(playbills.get(i).title.substring(0, 8) + "...");
} else {
tv.setText(playbills.get(i).title);
}
tv.setTextSize(12);
long id = playbills.get(i).id;
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MainJump.toThemePlaybillPage(activity, id);
}
});
addView(tv);
}
requestLayout();
}
}
自定义ViewGroup 流式布局
最新推荐文章于 2025-12-15 16:08:35 发布
此博客展示了 Android 中自定义视图组 FlowLayout 的代码实现。包含 onMeasure 方法测量子视图宽高以确定总高度和行宽,onLayout 方法对子视图进行布局,还有 addPlaybill 方法添加数据并设置子视图属性,如文本、点击事件等。
2277

被折叠的 条评论
为什么被折叠?



