android 实现流式布局FlowLayout

来源:互联网 发布:php true false 编辑:程序博客网 时间:2024/06/04 18:03


import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;


/**
 * @author YeGuangRong
 *
 */
public class FlowLayout extends ViewGroup{


public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}


public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}


public FlowLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}


/**
* 测量获取布局的宽和高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

/**
* 此部分可以获取Viewgroup为子View提供的测量模式和大小
*/
int widthSize   = MeasureSpec.getSize(widthMeasureSpec);
int widthMode   = MeasureSpec.getMode(widthMeasureSpec);
int heightSize  = MeasureSpec.getSize(heightMeasureSpec);
int heightMode  = MeasureSpec.getMode(heightMeasureSpec);

int childCount  = getChildCount();
int tatolHeight = 0;
int lineWidth   = 0;
int maxWidth    = 0;
//行数
int lineCount  = 0;

//需要将测量子View的测量模式设置为AT_MOST(对应类似于wrap_content),否则如果使用父类的测量模式会被设为EXACTLY,这样就达不到流的效果
int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);//如果使用EXACTLY的话每个子控件都会布满一行,就达不到我们需要的效果

//遍历子控件,对每个子控件进行测量,最后得出ViewGroup最终的宽度和高度
for(int i = 0; i< childCount; i++){

View childView = getChildAt(i);
childView.measure(newWidthMeasureSpec, heightMeasureSpec);//开始测量子控件

            MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();//获取空见设置的margin值,前提是重写generateLayoutParams(AttributeSet attrs)这个方法,见下文
            
            
if((lineWidth + childView.getMeasuredWidth() + marginLayoutParams.leftMargin+marginLayoutParams.rightMargin)>widthSize){//当空间叠加后所需要的宽度大于ViewGroup所能提供的最大宽度,则需要换行
tatolHeight = tatolHeight + childView.getMeasuredHeight()+marginLayoutParams.bottomMargin+marginLayoutParams.topMargin;
if(maxWidth < lineWidth){//将宽度最大的那一行作为最终ViewGroup的宽度
maxWidth = lineWidth;
}
lineWidth = childView.getMeasuredWidth()+marginLayoutParams.leftMargin+marginLayoutParams.rightMargin;
}else{//不换行的情况,在行内将子控件叠加
lineWidth = lineWidth + childView.getMeasuredWidth()+marginLayoutParams.leftMargin+marginLayoutParams.rightMargin;
if(tatolHeight == 0){
tatolHeight= childView.getMeasuredHeight()+marginLayoutParams.bottomMargin+marginLayoutParams.topMargin;
}
}
}


/**
* 设置ViewGroup最终的宽和高
*/
if(maxWidth != 0){
setMeasuredDimension(maxWidth, tatolHeight);
}else{
setMeasuredDimension(lineWidth, tatolHeight);
}
}


/**
* 上面确定ViewGroup的宽和高后,我们需要对ViewGroup里面的子控件进行摆放,确定每个控件的位置(位置可通过l,t,r,b四个值来设定)。
* l,是控件的左边距离父控件(此处即为该ViewGroup)的距离,通过getLeft()可获得其值
* t,是控件的上边距离距离其父控件的距离,通过getTop()可获得其值.
* r,是控件的右边距离距离其父控件的距离,通过getRight()可获得其值.
* b,是控件的底边距离距离其父控件的距离,通过getBottom()可获得其值.
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub

int childCount = getChildCount();
int left = 0,right = 0,top = 0,bottom = 0;
int measureWidth = getMeasuredWidth();
int measureHeight= getMeasuredHeight();
// Log.e("measureHeight", "measureHeight = "+measureHeight+" measureWidth = "+measureWidth);

for(int i = 0; i< childCount; i++){
View childView = getChildAt(i);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();
right          = left + childView.getMeasuredWidth()+marginLayoutParams.rightMargin;
bottom         = top + childView.getMeasuredHeight()+marginLayoutParams.bottomMargin;
if(i == 0){
left = marginLayoutParams.leftMargin;
}


if(right >= measureWidth){//如果摆放的子控件的右边大于ViewGroup的最大宽度 ,则将控件从下一行开始摆放
top  = bottom+marginLayoutParams.topMargin;
left = marginLayoutParams.leftMargin;
right= left + childView.getMeasuredWidth()+marginLayoutParams.rightMargin;
bottom    = top + childView.getMeasuredHeight()+marginLayoutParams.bottomMargin;
childView.layout(left, top, right, bottom);
left = right+marginLayoutParams.leftMargin;
}else{//不用换行时,从左到右摆放子控件
childView.layout(left, top, right, bottom);
left = right+marginLayoutParams.leftMargin;
}
}
}

@Override  
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs)  
{  
   return new MarginLayoutParams(getContext(), attrs);  
}  


}


1 0