package com.vansuita.materialabout.views; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; /** * Created by jrvansuita on 10/02/17. */ public final class AutoFitGridLayout extends ViewGroup { private int verticalSpace; private int horizontalSpace; private int columnCount = 2; private int childWidth; private ArrayList<View> notGoneViewList; public AutoFitGridLayout(Context context) { super(context); } public AutoFitGridLayout(Context context, AttributeSet attrs) { super(context, attrs); } public AutoFitGridLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private void refreshNotGoneChildList() { if (notGoneViewList == null) { notGoneViewList = new ArrayList<View>(); } notGoneViewList.clear(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child.getVisibility() != GONE) { notGoneViewList.add(child); } } } public int getVerticalSpace() { return verticalSpace; } public void setVerticalSpace(int verticalSpace) { this.verticalSpace = verticalSpace; requestLayout(); } public int getHorizontalSpace() { return horizontalSpace; } public void setHorizontalSpace(int horizontalSpace) { this.horizontalSpace = horizontalSpace; requestLayout(); } public int getColumnCount() { return columnCount; } public void setColumnCount(int columnCount) { this.columnCount = columnCount; requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { refreshNotGoneChildList(); if (childWidth <= 0) { final int parentWidth = MeasureSpec.getSize(widthMeasureSpec); childWidth = (int) ( (parentWidth - (columnCount - 1) * horizontalSpace * 1.0f) / columnCount + 0.5f); } int childCount = notGoneViewList.size(); int line = childCount % columnCount == 0 ? childCount / columnCount : childCount / columnCount + 1; int totalHeight = 0; int childIndex = 0; for (int i = 0; i < line; i++) { int inlineHeight = 0; for (int j = 0; j < columnCount; j++) { childIndex = i * columnCount + j; if (childIndex < childCount) { View child = notGoneViewList.get(childIndex); int childWidthWithPadding = childWidth; if (j == 0) { // measureChild会在size的基础上减掉paddingLeft和paddingRight,对于每一行第一个元素加上paddingRight抵消 childWidthWithPadding += getPaddingRight(); } else if (j == columnCount -1){ // measureChild会在size的基础上减掉paddingLeft和paddingRight,对于每一行最后一个元素加上paddingLeft抵消 childWidthWithPadding += getPaddingLeft(); } measureChild(child, MeasureSpec.makeMeasureSpec(childWidthWithPadding, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int totalInlineChildHeight = child.getMeasuredHeight(); if (totalInlineChildHeight > inlineHeight) { inlineHeight = totalInlineChildHeight; } } } totalHeight += inlineHeight; totalHeight += verticalSpace; } totalHeight -= verticalSpace; totalHeight += getPaddingTop() + getPaddingBottom(); setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), totalHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = notGoneViewList.size(); int line = childCount % columnCount == 0 ? childCount / columnCount : childCount / columnCount + 1; int childIndex = 0; int lastLeft = getPaddingLeft(); int lastTop = getPaddingTop(); for (int i = 0; i < line; i++) { int inlineHeight = 0; for (int j = 0; j < columnCount; j++) { childIndex = i * columnCount + j; if (childIndex < childCount) { View child = notGoneViewList.get(childIndex); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); child.layout(lastLeft, lastTop, lastLeft + childWidth, lastTop + childHeight); lastLeft += (childWidth + horizontalSpace); int totalInlineChildHeight = child.getMeasuredHeight(); if (totalInlineChildHeight > inlineHeight) { inlineHeight = totalInlineChildHeight; } } } lastLeft = getPaddingLeft(); lastTop += (inlineHeight + verticalSpace); } } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof LayoutParams; } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p); } public static class LayoutParams extends MarginLayoutParams { /** * {@inheritDoc} */ public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } /** * {@inheritDoc} */ public LayoutParams(int width, int height) { super(width, height); } /** * {@inheritDoc} */ public LayoutParams(ViewGroup.LayoutParams source) { super(source); } /** * {@inheritDoc} */ public LayoutParams(MarginLayoutParams source) { super(source); } /** * Copy constructor. Clones the width, height, margin values, and * gravity of the source. * * @param source The layout params to copy from. */ public LayoutParams(LayoutParams source) { super(source); } } }