package com.mcxtzhang.commonadapter.viewgroup.widget.fakergrid; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import com.mcxtzhang.commonadapter.R; /** * 介绍:模仿GridView的控件, * 用以替代、解决在列表中嵌套GridView的性能额外消耗问题。 * (性能额外消耗 :http://blog.csdn.net/zxt0601/article/details/52494665) * 作者:zhangxutong * 邮箱:mcxtzhang@163.com * 主页:http://blog.csdn.net/zxt0601 * 时间: 2016/12/27. */ public class FakerGridView extends ViewGroup { private static final int COLUMNS_DEFAULT = 1; //列数 private int mColumns; //每一列的间距 private int mHorizontalSpacing; //每一行的间距 private int mVerticalSpacing; private int mWidth, mHeight; //每一列的宽度 private int mPerColumnWidth; public FakerGridView(Context context) { this(context, null); } public FakerGridView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FakerGridView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr); } private void init(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FakerGridView, defStyleAttr, 0); int count = typedArray.getIndexCount(); for (int i = 0; i < count; i++) { int index = typedArray.getIndex(i); if (index == R.styleable.FakerGridView_numColumns) { mColumns = typedArray.getInteger(index, COLUMNS_DEFAULT); } else if (index == R.styleable.FakerGridView_horizontalSpacing) { mHorizontalSpacing = typedArray.getDimensionPixelOffset(index, 0); } else if (index == R.styleable.FakerGridView_verticalSpacing) { mVerticalSpacing = typedArray.getDimensionPixelOffset(index, 0); } } typedArray.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //获取系统传递过来测量出的宽度 高度,以及相应的测量模式。 //GridView主要是计算height的值 宽度 一般 match //如果测量模式为 EXACTLY( 确定的dp值,match_parent),则可以调用setMeasuredDimension()设置, //如果测量模式为 AT_MOST(wrap_content),则需要经过计算再去调用setMeasuredDimension()设置 int heightMeasure = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int childCount = getChildCount(); View child = null; int maxHeightPerline = 0; int computeHeight = 0; for (int i = 0; i < childCount; i++) { child = getChildAt(i); measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); maxHeightPerline = Math.max(maxHeightPerline, child.getMeasuredHeight()); //换行 或者 最后一个 都累加一下 if (i == childCount - 1) { computeHeight = computeHeight + maxHeightPerline; } else if (i % mColumns == mColumns - 1) { computeHeight = computeHeight + maxHeightPerline + mVerticalSpacing; maxHeightPerline = 0; } } setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), heightMode != MeasureSpec.EXACTLY ? computeHeight + getPaddingTop() + getPaddingBottom() : heightMeasure); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); mWidth = getWidth(); //这里如果考虑每个column的间距 则还需要修改 mPerColumnWidth = (mWidth - getPaddingRight() - getPaddingLeft() - mHorizontalSpacing * (mColumns - 1)) / mColumns; View child = null; int left = getPaddingLeft(); int top = getPaddingTop(); int maxHeightPerline = 0; for (int i = 0; i < childCount; i++) { child = getChildAt(i); child.layout(left, top, left + mPerColumnWidth, top + child.getMeasuredHeight()); maxHeightPerline = Math.max(maxHeightPerline, child.getMeasuredHeight()); //到达最后一列 if (i % mColumns == mColumns - 1) { left = getPaddingLeft(); top = top + maxHeightPerline + mVerticalSpacing; maxHeightPerline = 0; } else { left = left + mPerColumnWidth + mHorizontalSpacing; } } } /** * @return 当前ViewGroup返回的Params的类型 */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }