解决问题:
1、确定那个子控件应该放置到哪一行
2、对measure的高度测量进行核实防止高度计算错误
3、对于每行剩余的空间平均分配给每一个子控件
4、对于同一行元素的摆放使其能够在该行中居中显示
5、修正了在添加padding后控件显示不完全的问题
注意:只有在调用了measure方法后getMeasuredXXX才能获取到值,否则为0
正确获取控件大小,可以自己手动进行测量调用子view的measure方法
测量结束是在设置了setMeasuredimention之后
onmeasure方法会被调用两次,防止计算时出现错误
只有在调用了layout方法之后才能够拿到getXXX值
package chuang.sun.cn.flowlayout;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* Created by sunchuang on 2017/10/17.
*/
public class MyFlowLayout extends ViewGroup {
private static final int DEFAULT_SPACING = 20;
private int mHorizontalSpacing = DEFAULT_SPACING;
private int mVerticalSpacing = DEFAULT_SPACING;
private int mUsedWidth;
private int totalWidth;
private Line mCurrenLine;
private int measureHeight;
private List<Line> lineList = new ArrayList<>();
public MyFlowLayout(Context context) {
super(context);
init();
}
public MyFlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mCurrenLine = new Line();
lineList.add(mCurrenLine);
mUsedWidth = 0;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
reSet();
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int childCount = getChildCount();
totalWidth = widthSize - getPaddingLeft()-getPaddingRight();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
//如果view显示模式是Gone则不必测量
if(child.getVisibility() == View.GONE){
continue;
}
//获取子view的测量模式
int childWidthMeasureSpecMode = widthMode == MeasureSpec.EXACTLY?MeasureSpec.AT_MOST:widthMode;
int childHeightMeasureSpecMode = heightMode == MeasureSpec.EXACTLY?MeasureSpec.AT_MOST:heightMode;
//合成子view的MeasureSpec
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(totalWidth,childWidthMeasureSpecMode);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize,childHeightMeasureSpecMode);
child.measure(childWidthMeasureSpec,childHeightMeasureSpec);
//测量之后获取子控件的大小
int childWidth = child.getMeasuredWidth();
mUsedWidth += childWidth;
//如果该行还可以放下view则在该行放置View
if(mUsedWidth<=totalWidth){
mCurrenLine.addView(child);
mUsedWidth+=mHorizontalSpacing;
//如果加上空余的部分超出了每行的最大值那么就换行
if(mUsedWidth>totalWidth){
newLine();
}
}else{
//如果有哪行没有数据,需要进行添加保证每行至少有一条数据
if(mCurrenLine.getListCount() == 0){
mCurrenLine.addView(child);
mUsedWidth = totalWidth;
}else{
newLine();
mCurrenLine.addView(child);
mUsedWidth += childWidth + mHorizontalSpacing;
}
}
}
//根据行高计算出整个viewgroup的高度
for(int i = 0;i<lineList.size();i++){
measureHeight += lineList.get(i).mLineHeight+mVerticalSpacing;
}
measureHeight -= mVerticalSpacing;
measureHeight+=getPaddingBottom()+getPaddingTop();
setMeasuredDimension(widthSize,resolveSize(measureHeight,heightMeasureSpec));
}
private void newLine() {
mCurrenLine = new Line();
lineList.add(mCurrenLine);
mUsedWidth = 0;
}
private void reSet(){
mUsedWidth = 0;
measureHeight = 0;
lineList.clear();
mCurrenLine = new Line();
lineList.add(mCurrenLine);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int lineCount = lineList.size();
l = getPaddingLeft();
t = getPaddingBottom();
for(int i = 0;i<lineCount;i++){
Line line = lineList.get(i);
line.layoutView(l,t);
t+=line.mLineHeight+mVerticalSpacing;
}
}
class Line{
public int mLineWidth;
public int mLineHeight;
public List<View> viewList = new ArrayList<>();
private int splitSpacing;
public void addView(View view){
if(!viewList.contains(view)){
viewList.add(view);
//计算出每行使用的宽度以及每行的高度
mLineWidth += view.getMeasuredWidth()+mHorizontalSpacing;
mLineHeight = mLineHeight>view.getMeasuredHeight()?mLineHeight:view.getMeasuredHeight();
}
}
public int getListCount(){
return viewList.size();
}
public void layoutView(int left,int top){
int viewCount = getListCount();
int remainSpacing = getMeasuredWidth() - mLineWidth;
if(remainSpacing>0){//当有空余的时候平均分配
splitSpacing = remainSpacing/getListCount();
}
for(int i=0;i<viewCount;i++){
View mView = viewList.get(i);
int mViewHeight = mView.getMeasuredHeight();
int mViewWidth = mView.getMeasuredWidth();
int offsetHeight = (int) ((mLineHeight-mViewHeight)/2*1.0+0.5);
mViewWidth+=splitSpacing;
mView.getLayoutParams().width = mViewWidth;
//根据新计算的view大小及位置重新测量
mView.measure(MeasureSpec.makeMeasureSpec(mViewWidth,MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(mViewHeight,MeasureSpec.EXACTLY));
mView.layout(left,top+offsetHeight,left+mViewWidth,top+mViewHeight+offsetHeight);
//同一行中高度不变,只有x坐标在改变
left += mViewWidth +mHorizontalSpacing;
}
}
}
}