解决GridView高度计算不正确

解决GridView高度计算不正确

解决方案:
新建一个类继承GridView并重写onMeasure方法

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);//不要删除,不要屏蔽
        ListAdapter adapter = getAdapter();
        Class<?> gridClass = GridView.class;
        Class<?> absListView = gridClass.getSuperclass();
        int measuredHeight = getMeasuredHeight();
        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST && adapter != null) {
            int childCount = adapter.getCount();
            int height = getPaddingTop() + getPaddingBottom();
            int mColumnWidth = 0;
            try {
                Field mListPadding = absListView.getDeclaredField("mListPadding");
                mListPadding.setAccessible(true);
                Rect o = (Rect) mListPadding.get(this);
                height += o.top + o.bottom;
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                Field columnWidth = gridClass .getDeclaredField("mColumnWidth");
                columnWidth.setAccessible(true);
                mColumnWidth = (int) columnWidth.get(this);
            } catch (Exception e) {
                e.printStackTrace();
            }
            int singleHeight;
            int numColumns = getNumColumns();

            for (int i = 0; i < childCount; ) {
                singleHeight = 0;
                for (int j = 0; j < numColumns && i < childCount; i++, j++) {
                    View child = adapter.getView(i, null, this);// getChildAt(j);
                    ViewGroup.LayoutParams p = child.getLayoutParams();
                    if (mColumnWidth != 0) {
                        measureChild(child, MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
                    } else {
                        int width = MeasureSpec.getSize(widthMeasureSpec);
                        int singleWidth = (width - getHorizontalSpacing() * (numColumns - 1)) / numColumns;
                        measureChild(child, MeasureSpec.makeMeasureSpec(singleWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
                    }
                    int measuredHeight1 = child.getMeasuredHeight();
                    singleHeight = Math.max(singleHeight, measuredHeight1);
                }
                height += singleHeight + getVerticalSpacing();
            }
            setMeasuredDimension(getMeasuredWidth(), height > measuredHeight ? height : measuredHeight);
        }
    }

GridView中计算高度的代码片段:

 ...
 final View child = obtainView(0, mIsScrap);
 ...
 childHeight = child.getMeasuredHeight();
 ...

if (heightMode == MeasureSpec.AT_MOST) {
            int ourSize =  mListPadding.top + mListPadding.bottom;

            final int numColumns = mNumColumns;
            for (int i = 0; i < count; i += numColumns) {
                ourSize += childHeight;
                if (i + numColumns < count) {
                    ourSize += mVerticalSpacing;
                }
                if (ourSize >= heightSize) {
                    ourSize = heightSize;
                    break;
                }
            }
            heightSize = ourSize;
        }

系统的GridView在计算高度的时候为了提高效率,在GridView设置高度为wrap_content时高度计算默认第一行第一列的高度为基准高度计算GridView整体高度。如果出现第二列比第一列高度高则会出现高度计算不准确,必须通过上下滑动才能显示完整内容。
解决以上问题的方法就是遍历所有子view。并计算所有子View宽高。
高度计算有以下难点:
难点一:
高度需要加上mListPadding.top与mListPadding.bottom高度。mListPadding不能在子类中获取,需要通过反射获取。其声明在AbsListView中。
难点二:
测量子View宽高,在GridView中有mColumnWidth成员变量可以直接使用。但是必须通过反射获取。如果获取不到,做了一个兼容:

int singleWidth = (width - getHorizontalSpacing() * (numColumns - 1)) / numColumns;

getHorizontalSpacing() * (numColumns - 1) 对应 列间距 * (列数-1)得到空白区域宽度。
此处计算每个item最大宽度。当然有可能计算不准确。在此,measureChild()方法中宽度spec一般情况下不要用widthMeasureSpec。有可能导致高度计算不准确。
如有错误请指正。

发布了9 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/spyunknow/article/details/78054926