先看效果圖吧,
繼上一篇《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; } }
所有demo工程點擊這里下載:click me!!!
