FlowLayout.java
-
package cn.com.xiebiao.flowlayout;
-
-
import android.content.Context;
-
import android.util.AttributeSet;
-
import android.view.View;
-
import android.view.ViewGroup;
-
-
import java.util.ArrayList;
-
import java.util.List;
-
-
/**
-
* Created by vibexie on 3/26/15.
-
*/
-
public class FlowLayout extends ViewGroup{
-
-
//三个构造方法
-
public FlowLayout(Context context) {
-
//super(context);
-
this(context,null);
-
}
-
-
public FlowLayout(Context context, AttributeSet attrs) {
-
//super(context, attrs);
-
this(context,attrs,0);
-
-
}
-
-
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
}
-
-
//当前ViewGroup对应的LayoutParams
-
@Override
-
public LayoutParams generateLayoutParams(AttributeSet attrs) {
-
return new MarginLayoutParams(getContext(),attrs);
-
}
-
-
/*widthMeasureSpec,heightMeasureSpec分别为
-
*android:layout_width="match_parent" android:layout_height="match_parent">
-
* 也就是父ViewGroup传递进来的值
-
*/
-
@Override
-
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
/*容器ViewGroup的宽度和模式,android:layout_width="match_parent"对应模式MeasureSpec.EXACTLY;
-
android:layout_width="match_parent"对应模式MeasureSpec.AT_MOST;
-
还有一种模式不常用MeasureSpec.UNSPECIFIED
-
*/
-
int sizeWidth=MeasureSpec.getSize(widthMeasureSpec);
-
int modeWidth=MeasureSpec.getMode(widthMeasureSpec);
-
/*容器ViewGroup的宽度和模式,同width*/
-
int sizeHeigth=MeasureSpec.getSize(heightMeasureSpec);
-
int modeHeigth=MeasureSpec.getMode(heightMeasureSpec);
-
-
/*如上,是match_parent的时候,sizeWidth和sizeHeigth可以在父viewGroup中得到
-
但是如果是warp_content时,就需要自己计算sizeWidth和sizeHeigth
-
*/
-
//记录最大宽度和最大高度对应的宽和高
-
int width=0;
-
int heigth=0;
-
//记录每一行的宽度和高度
-
int lineWidth=0;
-
int lineHeigth=0;
-
//得到内部元素的个数
-
int cCount=getChildCount();
-
-
//遍历子View
-
for(int i=0;i<cCount;i++){
-
View child=getChildAt(i);
-
-
/*测量子view的宽和高
-
protected void measureChild(android.view.View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)
-
*/
-
measureChild(child,widthMeasureSpec,heightMeasureSpec);
-
-
/*得到LayoutParams,必须由于父View的LayoutParams相一致,
-
即与public LayoutParams generateLayoutParams(AttributeSet attrs)返回的一致
-
*/
-
MarginLayoutParams layoutParams=(MarginLayoutParams)child.getLayoutParams();
-
-
//子View占据的宽度
-
int childWidth=child.getMeasuredWidth()+layoutParams.leftMargin+layoutParams.rightMargin;
-
//子View占据的高度
-
int childHeigth=child.getMeasuredHeight()+layoutParams.topMargin+layoutParams.bottomMargin;
-
-
if((lineWidth+childWidth)>sizeWidth){
-
//如果此行的宽度+下一个子View的宽度大于容器ViewGroup的宽度,则换行
-
//记录的最大宽度width和本行的宽度lineWidth比较,得到最大的宽度再记录
-
width=Math.max(width,lineWidth);
-
//重置lineWidth
-
lineWidth=childWidth;
-
//记录行高
-
heigth+=lineHeigth;
-
//重置lineHeigth
-
lineHeigth=childHeigth;
-
}else {
-
//不换行
-
//叠加行宽
-
lineWidth+=childWidth;
-
//得到当前行最到的高度
-
lineHeigth=Math.max(lineHeigth,childHeigth);
-
}
-
-
if(i==cCount-1){
-
//到达最后一个子view
-
width=Math.max(lineWidth,width);
-
heigth+=lineHeigth;
-
}
-
}
-
-
//设定最终尺寸
-
setMeasuredDimension(modeWidth==MeasureSpec.EXACTLY?sizeWidth:width,modeHeigth==MeasureSpec.EXACTLY?sizeHeigth:heigth);
-
-
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
}
-
-
//保存所有的View,以分行的方式保存
-
private List<List<View>> mAllViews=new ArrayList<List<View>>();
-
-
//每一行的高度
-
private List<Integer> mLineHeigth=new ArrayList<Integer>();
-
-
@Override
-
protected void onLayout(boolean b, int i, int i2, int i3, int i4) {
-
//调用多次onlayout方法时,清空保存的内容
-
mAllViews.clear();
-
mLineHeigth.clear();
-
-
//当前ViewGroup的宽度,之前已经执行了onMesure()方法
-
int width=getWidth();
-
-
int lineWidth=0;
-
int lineHeigth=0;
-
-
//存放每一行的View
-
List<View> lineViews=new ArrayList<View>();
-
-
//子View的个数
-
int cCount=getChildCount();
-
-
for(int j=0;j<cCount;j++){
-
View child=getChildAt(j);
-
MarginLayoutParams layoutParams=(MarginLayoutParams)child.getLayoutParams();
-
-
int childWidth=child.getMeasuredWidth();
-
int childHeigth=child.getMeasuredHeight();
-
-
//如果需要换行
-
if((childWidth+lineWidth+layoutParams.leftMargin+layoutParams.rightMargin)>width){
-
//记录lineHeigth
-
mLineHeigth.add(lineHeigth);
-
//记录当前的view
-
mAllViews.add(lineViews);
-
-
//重置行宽和行高
-
lineWidth=0;
-
lineHeigth=childHeigth+layoutParams.topMargin+layoutParams.bottomMargin;
-
-
//重置lineViews集合
-
lineViews=new ArrayList<View>();
-
}
-
-
//不换行则将child加入lineViews中
-
lineWidth+=childWidth+layoutParams.leftMargin+layoutParams.rightMargin;
-
lineHeigth=Math.max(lineHeigth,childHeigth+layoutParams.topMargin+layoutParams.bottomMargin);
-
lineViews.add(child);
-
}
-
-
//处理最后一行
-
mLineHeigth.add(lineHeigth);
-
mAllViews.add(lineViews);
-
-
-
//处理子View的位置
-
int left=0;
-
int top=0;
-
-
//行数
-
int lineNum=mAllViews.size();
-
-
for(int j=0;j<lineNum;j++){
-
//当前行的所有View
-
lineViews=mAllViews.get(j);
-
lineHeigth=mLineHeigth.get(j);
-
-
for(int k=0;k<lineViews.size();k++){
-
View child=lineViews.get(k);
-
-
//判断child的状态
-
if(child.getVisibility()==View.GONE){
-
continue;
-
}
-
-
MarginLayoutParams layoutParams=(MarginLayoutParams)child.getLayoutParams();
-
-
int lc=left+layoutParams.leftMargin;
-
int tc=top+layoutParams.topMargin;
-
int rc=lc+child.getMeasuredWidth();
-
int bc=tc+child.getMeasuredHeight();
-
-
//为子View布局
-
child.layout(lc,tc,rc,bc);
-
-
left+=child.getMeasuredWidth()+layoutParams.leftMargin+layoutParams.rightMargin;
-
}
-
-
//到达下一行
-
left=0;
-
top+=lineHeigth;
-
}
-
}
- }
activity_main.xml
-
<RelativeLayout xmlns:android=""
-
xmlns:tools="" android:layout_width="match_parent"
-
android:layout_height="match_parent" >
-
-
<cn.com.xiebiao.flowlayout.FlowLayout
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content">
-
<Button
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="hello"/>
-
<Button
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="welocom"/>
-
<Button
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="fdsfsd"/>
-
<Button
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="fdsfdsgdgdfgdfgf"/>
-
<Button
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="ghfdhdgfhdfghdgfh"/>
-
<Button
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:text="ggg"/>
-
-
</cn.com.xiebiao.flowlayout.FlowLayout>
-
- </RelativeLayout>
MainActivity.java
-
package cn.com.xiebiao.flowlayout;
-
-
import android.app.Activity;
-
import android.os.Bundle;
-
import android.view.Menu;
-
import android.view.MenuItem;
-
-
-
public class MainActivity extends Activity {
-
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.activity_main);
-
}
-
-
-
@Override
-
public boolean onCreateOptionsMenu(Menu menu) {
-
// Inflate the menu; this adds items to the action bar if it is present.
-
getMenuInflater().inflate(R.menu.menu_main, menu);
-
return true;
-
}
-
-
@Override
-
public boolean onOptionsItemSelected(MenuItem item) {
-
// Handle action bar item clicks here. The action bar will
-
// automatically handle clicks on the Home/Up button, so long
-
// as you specify a parent activity in AndroidManifest.xml.
-
int id = item.getItemId();
-
-
//noinspection SimplifiableIfStatement
-
if (id == R.id.action_settings) {
-
return true;
-
}
-
-
return super.onOptionsItemSelected(item);
-
}
- }