解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题详解手机开发

我们先看一个效果,问题说的就是中间的Grid效果在Scrollview 嵌套recyclerview显示问题,在Android Api 24是好的,不过在5,1,1版本(api 22)缺出现了问题

解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题详解手机开发

最近项目中,有一个商品详情页面,页面有好几个网格页面,大家说,我们大可以用GridView去做,但是需要方的要求是,我们的网格的中间的线怎么做呢,对于GridView,我们知道我们可以这是一个背景,然后用verticalSpacing来做,这也算一个方法吧,但是对于Line线的计算是一个问题,有很多的计算逻辑,这样对代码的美观就造成了破坏,且看一段之前的代码:

private void computeCompanyGridViewHeight(int size) { 
		S.p("computeCompanyGridViewHeight size:" + size); 
		if (size > 9) { 
			size = 9; 
		} 
		int len = 3; 
		if (size % 3 == 0) { 
			len = size / 3 - 1; 
		} else { 
			len = size / 3; 
		} 
		int height = (len + 1) * Utils.dip2px(getActivity(), 58); 
		ship_mid_companys.getLayoutParams().height = height; 
	}

我们这里采用RecycleView来实现。以前在ScrollView中嵌套嵌套ListView,无法正确的计算ListView的大小,现在我们在ScrollView中嵌套嵌套RecycleView的时候,也出现了计算不出高度的问题,于是有人想到我们是不是可以自己实现一个重写一个继承自RecycleView的类,重写OmMeasure,呵呵,但是实际上这是不行的,RecycleView是具体的一个控件,不相同与我们的ListView,这里参照之前网上的解决方案,我们可以继承自GridManager,然后对OnMeasure重写,其他的列表效果如此,

public class WrappingGridLayoutManager extends GridLayoutManager { 
 
        private int mwidth = 0; 
        private int mheight = 0; 
 
        public WrappingGridLayoutManager(Context context, int spanCount) { 
            super(context, spanCount); 
        } 
 
        public WrappingGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { 
            super(context, spanCount, orientation, reverseLayout); 
        } 
 
        private int[] mMeasuredDimension = new int[2]; 
 
        public int getMwidth() { 
            return mwidth; 
        } 
 
        public void setMwidth(int mwidth) { 
            this.mwidth = mwidth; 
        } 
 
        public int getMheight() { 
            return mheight; 
        } 
 
        public void setMheight(int mheight) { 
            this.mheight = mheight; 
        } 
 
        @Override 
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { 
            final int widthMode = View.MeasureSpec.getMode(widthSpec); 
            final int heightMode = View.MeasureSpec.getMode(heightSpec); 
            final int widthSize = View.MeasureSpec.getSize(widthSpec); 
            final int heightSize = View.MeasureSpec.getSize(heightSpec); 
 
            int width = 0; 
            int height = 0; 
            int count = getItemCount(); 
            int span = getSpanCount(); 
            for (int i = 0; i < count; i++) { 
                measureScrapChild(recycler, i, 
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 
                        mMeasuredDimension); 
 
                if (getOrientation() == HORIZONTAL) { 
                    if (i % span == 0) { 
                        width = width + mMeasuredDimension[0]; 
                    } 
                    if (i == 0) { 
                        height = mMeasuredDimension[1]; 
                    } 
                } else { 
                    if (i % span == 0) { 
                        height = height + mMeasuredDimension[1]; 
                    } 
                    if (i == 0) { 
                        width = mMeasuredDimension[0]; 
                    } 
                } 
            } 
 
            switch (widthMode) { 
                case View.MeasureSpec.EXACTLY: 
                    width = widthSize; 
                case View.MeasureSpec.AT_MOST: 
                case View.MeasureSpec.UNSPECIFIED: 
            } 
 
            switch (heightMode) { 
                case View.MeasureSpec.EXACTLY: 
                    height = heightSize; 
                case View.MeasureSpec.AT_MOST: 
                case View.MeasureSpec.UNSPECIFIED: 
            } 
            setMheight(height); 
            setMwidth(width); 
            setMeasuredDimension(width, height); 
        } 
 
        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, 
                                       int heightSpec, int[] measuredDimension) { 
            if (position < getItemCount()) { 
                try { 
                    View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException 
                    if (view != null) { 
                        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); 
                        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, 
                                getPaddingLeft() + getPaddingRight(), p.width); 
                        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, 
                                getPaddingTop() + getPaddingBottom(), p.height); 
                        view.measure(childWidthSpec, childHeightSpec); 
                        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; 
                        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; 
                        recycler.recycleView(view); 
                    } 
                } catch (Exception e) { 
                    e.printStackTrace(); 
                } 
            } 
    } 
}
 private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, 
                                       int heightSpec, int[] measuredDimension) { 
            if (position < getItemCount()) { 
                try { 
                    View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException 
                    if (view != null) { 
                        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); 
                        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, 
                                getPaddingLeft() + getPaddingRight(), p.width); 
                        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, 
                                getPaddingTop() + getPaddingBottom(), p.height); 
                        view.measure(childWidthSpec, childHeightSpec); 
                        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; 
                        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; 
                        recycler.recycleView(view); 
                    } 
                } catch (Exception e) { 
                    e.printStackTrace(); 
                } 
            } 
    }

至于划线,我们需要另一个类实现,这用到了Recycle的一个方法

recyclerView.addItemDecoration(new SupportGridItemLine(this));

Line线计算类:

public class SupportGridItemLine extends RecyclerView.ItemDecoration { 
 
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; 
    private Drawable mDivider; 
 
    public SupportGridItemLine(Context context) { 
        final TypedArray a = context.obtainStyledAttributes(ATTRS); 
        mDivider = a.getDrawable(0); 
        a.recycle(); 
    } 
 
    @Override 
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 
 
        drawHorizontal(c, parent); 
        drawVertical(c, parent); 
 
    } 
 
    private int getSpanCount(RecyclerView parent) { 
        // 列数 
        int spanCount = -1; 
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); 
        if (layoutManager instanceof GridLayoutManager) { 
 
            spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); 
        } else if (layoutManager instanceof StaggeredGridLayoutManager) { 
            spanCount = ((StaggeredGridLayoutManager) layoutManager) 
                    .getSpanCount(); 
        } 
        return spanCount; 
    } 
 
    public void drawHorizontal(Canvas c, RecyclerView parent) { 
        int childCount = parent.getChildCount(); 
        for (int i = 0; i < childCount; i++) { 
            final View child = parent.getChildAt(i); 
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 
                    .getLayoutParams(); 
            final int left = child.getLeft() - params.leftMargin; 
            final int right = child.getRight() + params.rightMargin 
                    + mDivider.getIntrinsicWidth(); 
            final int top = child.getBottom() + params.bottomMargin; 
            final int bottom = top + mDivider.getIntrinsicHeight(); 
            mDivider.setBounds(left, top, right, bottom); 
            mDivider.draw(c); 
        } 
    } 
 
    public void drawVertical(Canvas c, RecyclerView parent) { 
        final int childCount = parent.getChildCount(); 
        for (int i = 0; i < childCount; i++) { 
            final View child = parent.getChildAt(i); 
 
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 
                    .getLayoutParams(); 
            final int top = child.getTop() - params.topMargin; 
            final int bottom = child.getBottom() + params.bottomMargin; 
            final int left = child.getRight() + params.rightMargin; 
            final int right = left + mDivider.getIntrinsicWidth(); 
 
            mDivider.setBounds(left, top, right, bottom); 
            mDivider.draw(c); 
        } 
    } 
 
    private boolean isLastColum(RecyclerView parent, int pos, int spanCount, 
                                int childCount) { 
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); 
        if (layoutManager instanceof GridLayoutManager) { 
            if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边 
            { 
                return true; 
            } 
        } else if (layoutManager instanceof StaggeredGridLayoutManager) { 
            int orientation = ((StaggeredGridLayoutManager) layoutManager) 
                    .getOrientation(); 
            if (orientation == StaggeredGridLayoutManager.VERTICAL) { 
                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边 
                { 
                    return true; 
                } 
            } else { 
                childCount = childCount - childCount % spanCount; 
                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边 
                    return true; 
            } 
        } 
        return false; 
    } 
 
    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, 
                              int childCount) { 
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); 
        if (layoutManager instanceof GridLayoutManager) { 
            childCount = childCount - childCount % spanCount; 
            if (pos >= childCount)// 如果是最后一行,则不需要绘制底部 
                return true; 
        } else if (layoutManager instanceof StaggeredGridLayoutManager) { 
            int orientation = ((StaggeredGridLayoutManager) layoutManager) 
                    .getOrientation(); 
            // StaggeredGridLayoutManager 且纵向滚动 
            if (orientation == StaggeredGridLayoutManager.VERTICAL) { 
                childCount = childCount - childCount % spanCount; 
                // 如果是最后一行,则不需要绘制底部 
                if (pos >= childCount) 
                    return true; 
            } else 
            // StaggeredGridLayoutManager 且横向滚动 
            { 
                // 如果是最后一行,则不需要绘制底部 
                if ((pos + 1) % spanCount == 0) { 
                    return true; 
                } 
            } 
        } 
        return false; 
    } 
 
    @Override 
    public void getItemOffsets(Rect outRect, int itemPosition, 
                               RecyclerView parent) { 
        int spanCount = getSpanCount(parent); 
        int childCount = parent.getAdapter().getItemCount(); 
        if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部 
        { 
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 
        } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边 
        { 
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 
        } else { 
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 
                    mDivider.getIntrinsicHeight()); 
        } 
    } 
}

好了,最后我们在使用的时候,先对RecycleView初始化相关的属性参数:

 WrappingGridLayoutManager manager = new WrappingGridLayoutManager(getActivity(), 2);//2表示2个单元格 
        manager.setOrientation(GridLayoutManager.VERTICAL); 
        manager.setSmoothScrollbarEnabled(true); 
        recyclerView.setLayoutManager(manager); 
        recyclerView.setHasFixedSize(true); 
        recyclerView.setNestedScrollingEnabled(false); 
        recyclerView.addItemDecoration(new SupportGridItemLine(getActivity()));

至于网上有人说的,在RecycleView外加一个布局,不知道什么原因,我这里还是没有解决。

 <RelativeLayout 
                android:layout_width="match_parent" 
                android:layout_height="wrap_content" 
                android:descendantFocusability="blocksDescendants"> 
                <android.support.v7.widget.RecyclerView 
                    android:id="@+id/menuRv" 
                    android:layout_width="match_parent" 
                    android:layout_height="wrap_content" 
                    android:layout_marginLeft="@dimen/margin_16" 
                    android:layout_marginRight="@dimen/margin_16"> 
 
                </android.support.v7.widget.RecyclerView> 
                </RelativeLayout>

好了,姑且记下,帮助后来人,有疑问请加群:278792776

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/5664.html

(0)
上一篇 2021年7月17日
下一篇 2021年7月17日

相关推荐

发表回复

登录后才能评论