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

最近项目中,有一个商品详情页面,页面有好几个网格页面,大家说,我们大可以用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

解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题的更多相关文章

  1. 解决ScrollView嵌套RecyclerView的显示及滑动问题

        项目中时常需要实现在ScrollView中嵌入一个或多个RecyclerView.这一做法通常会导致如下几个问题 页面滑动卡顿 ScrollView高度显示不正常 RecyclerView内容 ...

  2. 一键解决ScrollView嵌套ListView仅仅显示一行的问题

    /** * 解决ScrollView嵌套ListView仅仅显示一行的问题 * * @param listView */ private void setListViewHeightBasedOnCh ...

  3. 解决ScrollView嵌套RecyclerView出现item显示不全的问题

      问题:ScrollView嵌套RecyclerView时,RecyclerView的item显示不全 出现问题不要慌,耐心解决才是王道,哈哈.首先说下出现这个问题的情景吧,首先声明这个问题在23版 ...

  4. Android在开发中的使用技巧之解决ScrollView嵌套RecyclerView出现的系列问题

    根据已上线的app里总结出来的实用小技巧 相信大家都遇到过ScrollView嵌套RecyclerView或者RecyclerView嵌套RecyclerView来使用, 也会遇到一堆奇奇怪怪的问题, ...

  5. Android 解决ScrollView嵌套RecyclerView导致滑动不流畅的问题

    最近做的项目中遇到了ScrollView嵌套RecyclerView,刚写完功能测试,直接卡出翔了,后来通过网上查找资料和 自己的实践,找出了两种方法解决这个问题. 首先来个最简单的方法: recyc ...

  6. 解决ScrollView 嵌套 GridView 单行显示问题

    简单重写GridView package com.hh.beauter.my_ui; import android.content.Context; import android.util.Attri ...

  7. ScrollView嵌套ListView只显示一行之计算的高度不正确的解决办法(转)

    ScrollView嵌套ListView只显示一行之计算的高度不正确的解决办法 分类: android应用开发2013-12-19 09:40 1045人阅读 评论(3) 收藏 举报 AndroidS ...

  8. Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

    标签:scrollview   android   滑动   嵌套 scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview ...

  9. (转载) Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

    Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题 标签: scrollviewandroid滑动嵌套 2015-07-16 17:24 1112 ...

随机推荐

  1. 【poj 1087 a plug for UNIX】

    在大米饼的帮助下,终于找到了大米饼程序中如同大米饼一般的错误! 考点在问题转化,然后就跑一个你喜欢的最大流算法(二分图可以啵?) 再来一个例子吧: [纯手绘大米饼图片] 其中有的边权是1,否则就是in ...

  2. 习题10-1 UVA 11040(无聊水一水)

    题意: 给你一个残缺的塔,每个数字由他下面左右两个数相加得.给你其中一部分,要求输出全部的数字. #include <iostream> #include <cstdio> # ...

  3. poj 2417 && poj3243(Baby-Step Giant-Step)

    Discrete Logging Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4624   Accepted: 2113 ...

  4. c语言第六次作业v

    (一)改错题 序列求和:输入一个正实数eps,计算序列部分和 1 - 1/4 + 1/7 - 1/10 + ... ,精确到最后一项的绝对值小于eps(保留6位小数). 输入输出样例: Input e ...

  5. windows server 2008 R2 NPS(网络连接策略服务)设置radius,实现telent登陆交换机路由器权限分配

    windows2008NPS(网络连接策略)设置radius 实现telent登陆交换机路由器权限分配 转载请说明出处 一,安装 首先在08中添加服务器角色网络策略和访问服务(Network Poli ...

  6. (MariaDB)开窗函数用法

    本文目录: 1.1 窗口和开窗函数简介 1.2 OVER()语法和执行位置 1.3 row_number()对分区排名 1.4 rank()和dense_rank() 1.5 percent_rank ...

  7. PLSQL(2)

      游标                      [1] 不带参数的游标 -- 取出EMP表中的所有人名字 DECLARE CURSOR C IS SELECT * FROM EMP; V_EMP ...

  8. mysql数据库索引类型和原理

    索引初识: 最普通的情况,是为出现在where子句的字段建一个索引.为方便讲述,我们先建立一个如下的表. CREATE TABLE mytable ( id serial primary key, c ...

  9. scan函数用法详解

    scan函数: scan(s,n,"char")表示从字串string中以char为分隔符提取第n个字串 功能(function):从字符表达式s中搜取给定的n个单词语法(synt ...

  10. python3.6 使用 pymysql 连接 Mysql 数据库及 简单的增删改查操作

    1.通过 pip 安装 pymysql 进入 cmd  输入  pip install pymysql   回车等待安装完成: 安装完成后出现如图相关信息,表示安装成功. 2.测试连接 import ...