先看效果图吧,
继上一篇《android自定义viewgroup实现等分格子布局》中实现的布局效果,这里稍微有些区别,每个格子的高度不规则,就是传说的瀑布流布局,一般实现这种效果,要么用第三方控件,如果不是加载图片还可以直接写在xml中实现,不过代码会很多的;
下面我重写了viewgroup,实现 onMeasure,onLayout方法,动态设置每个布局的高度,这里有一个小的技巧,一般我们自定义的控件,嵌套在scrollview中显示不 全,这个问题也纠结我一小会,不过当你打开scrollview的源码,你会发现有一个地方,同时可以理解scrollview中嵌套 viewpager,gridview,listview时候会显示不全的问题
下面是自定义viewgroup的全部代码:
package com.allen.view;
import com.allen.mygridlayout.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
/**
* @package:com.fumei.letao.views
* @author:Allen
* @email:jaylong1302@163.com
* @data:2013年11月26日 下午8:39:51
* @description:瀑布流视图
*/
public class WaterfullLayout extends ViewGroup {
final String tag = "balance";
// 列数
int columns = 2;
// 行数
int rows = 0;
// 边距
int margin = 10;
// 子视图数量
int count = 0;
private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
public WaterfullLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.MyGridLayout);
columns = a.getInteger(R.styleable.MyGridLayout_numColumns, 2);
margin = (int) a.getInteger(R.styleable.MyGridLayout_itemMargin, 2);
}
}
public WaterfullLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public WaterfullLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxChildWidth = 0;
mMaxChildHeight = 0;
count = getChildCount();
if (count == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
rows = count % columns == 0 ? count / columns : count / columns + 1;// 行数
int top[] = new int[columns];
for (int i = 0; i < rows; i++) {// 遍历行
for (int j = 0; j < columns; j++) {// 遍历每一行的元素
View child = this.getChildAt(i * columns + j);
if (child == null)
break;
ViewGroup.LayoutParams lp = child.getLayoutParams();
if (child.getVisibility() == GONE) {
continue;
}
child.measure(MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
lp.height, MeasureSpec.AT_MOST));
top[j] += lp.height + margin;
mMaxChildWidth = Math.max(mMaxChildWidth,
child.getMeasuredWidth());
}
}
setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec),
resolveSize(getMax(top) + margin, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
int height = b - t;// 布局区域高度
int width = r - l;// 布局区域宽度
if (count == 0)
return;
int gridW = (width - margin * (columns + 1)) / columns;// 格子宽度
int gridH = 0;// 格子高度
int left = 0;
int top[] = new int[columns];
for (int i = 0; i < rows; i++) {// 遍历行
for (int j = 0; j < columns; j++) {// 遍历每一行的元素
View child = this.getChildAt(i * columns + j);
if (child == null)
return;
ViewGroup.LayoutParams lp = child.getLayoutParams();
child.measure(MeasureSpec.makeMeasureSpec(gridW,
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
lp.height, MeasureSpec.AT_MOST));
// 如果最后有一个对其的标志,为了底部对其
if (child.getTag() != null && child.getTag().equals(tag)) {
child.measure(MeasureSpec.makeMeasureSpec(gridW,
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMax(top) - top[j], MeasureSpec.EXACTLY));
gridH = getMax(top) - top[j];
left = j * gridW + margin * (j + 1);
child.layout(left, top[j] + margin, left + gridW, top[j]
+ gridH);
break;
}
gridH = lp.height;
left = j * gridW + margin * (j + 1);
top[j] += margin;
child.layout(left, top[j], left + gridW, top[j] + gridH);
top[j] += gridH;
}
}
}
/** 计算整体布局高度,为了在嵌套在scrollview中能显示出来 */
private int getMax(int array[]) {
int max = array[0];
for (int i = 0; i < array.length; i++) {
if (max < array[i])
max = array[i];
}
return max;
}
}